├── .gitignore
├── .travis.yml
├── LICENSE.txt
├── MANIFEST.in
├── README.rst
├── docs
├── Makefile
├── api
│ ├── clients.rst
│ ├── common.rst
│ ├── constants.rst
│ ├── libtaxii.rst
│ ├── messages_10.rst
│ ├── messages_11.rst
│ ├── modules.rst
│ ├── query.rst
│ └── validation.rst
├── changes.rst
├── conf.py
├── getting_started.rst
├── index.rst
├── installation.rst
├── make.bat
└── scripts.rst
├── libtaxii
├── __init__.py
├── clients.py
├── common.py
├── constants.py
├── messages.py
├── messages_10.py
├── messages_11.py
├── scripts
│ ├── __init__.py
│ ├── collection_information_client.py
│ ├── discovery_client.py
│ ├── discovery_client_10.py
│ ├── feed_information_client_10.py
│ ├── fulfillment_client.py
│ ├── inbox_client.py
│ ├── inbox_client_10.py
│ ├── poll_client.py
│ ├── poll_client_10.py
│ └── query_client.py
├── taxii_default_query.py
├── test
│ ├── __init__.py
│ ├── argument_parser_test.py
│ ├── clients_test.py
│ ├── data
│ │ └── configuration.ini
│ ├── input
│ │ └── 1.1
│ │ │ ├── Collection_Information_Response.xml
│ │ │ ├── Discovery_Response.xml
│ │ │ ├── Inbox_Message.xml
│ │ │ ├── Subscription_Management_Request.xml
│ │ │ └── Subscription_Management_Response.xml
│ ├── messages_10_test.py
│ ├── messages_11_test.py
│ ├── output
│ │ └── 1.1
│ │ │ └── readme.md
│ ├── test_clients.py
│ ├── test_xml_encoding.py
│ ├── to_text_11_test.py
│ └── validation_test.py
├── validation.py
├── version.py
└── xsd
│ ├── TAXII_DefaultQuery_Schema.xsd
│ ├── TAXII_XMLMessageBinding_Schema.xsd
│ ├── TAXII_XMLMessageBinding_Schema_11.xsd
│ └── xmldsig-core-schema.xsd
├── requirements.txt
├── setup.cfg
├── setup.py
└── tox.ini
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.swp
3 | *.swo
4 | build/
5 | dist/
6 | libtaxii.egg-info/
7 | venv/
8 | .pytest_cache
9 | .tox
10 | output.txt
11 | libtaxii/test/output/
12 | docs/_build/
13 | .idea
14 | .cache
15 | .coverage
16 | htmlcov/
17 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | os: linux
2 | language: python
3 | cache: pip
4 | dist: xenial
5 | python:
6 | - "2.7"
7 | - "3.4"
8 | - "3.5"
9 | - "3.6"
10 | - "3.7"
11 | - "3.8"
12 | matrix:
13 | include:
14 | # https://blog.travis-ci.com/2019-04-15-xenial-default-build-environment
15 | # https://travis-ci.community/t/issue-with-python-2-6-on-linux/3861/2
16 | - python: 2.6
17 | dist: trusty
18 | install:
19 | - pip install -U pip setuptools
20 | - pip install tox-travis
21 | script: tox
22 | notifications:
23 | email:
24 | - stix-commits-list@groups.mitre.org
25 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017, The MITRE Corporation
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 | * Redistributions of source code must retain the above copyright
7 | notice, this list of conditions and the following disclaimer.
8 | * Redistributions in binary form must reproduce the above copyright
9 | notice, this list of conditions and the following disclaimer in the
10 | documentation and/or other materials provided with the distribution.
11 | * Neither the name of The MITRE Corporation nor the
12 | names of its contributors may be used to endorse or promote products
13 | derived from this software without specific prior written permission.
14 |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include LICENSE.txt
2 | include README.rst
3 | include libtaxii/xsd/*.xsd
4 | include requirements.txt
5 | recursive-include docs *
6 | recursive-exclude docs *.pyc
7 | recursive-exclude docs *.pyo
8 | prune docs/_build
9 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | libtaxii
2 | ========
3 |
4 | A Python library for handling `Trusted Automated eXchange of Indicator Information (TAXII™) `_ v1.x Messages and invoking TAXII Services.
5 |
6 | :Source: https://github.com/TAXIIProject/libtaxii/
7 | :Documentation: https://libtaxii.readthedocs.io/
8 | :Information: https://taxiiproject.github.io/
9 | :Download: https://pypi.python.org/pypi/libtaxii/
10 |
11 | |travis badge| |landscape.io badge| |version badge| |downloads badge|
12 |
13 | .. |travis badge| image:: https://api.travis-ci.org/TAXIIProject/libtaxii.svg?branch=master
14 | :target: https://travis-ci.org/TAXIIProject/libtaxii
15 | :alt: Build Status
16 | .. |landscape.io badge| image:: https://landscape.io/github/TAXIIProject/libtaxii/master/landscape.svg?style=flat
17 | :target: https://landscape.io/github/TAXIIProject/libtaxii/master
18 | :alt: Code Health
19 | .. |version badge| image:: https://img.shields.io/pypi/v/libtaxii.svg?maxAge=3600
20 | :target: https://pypi.python.org/pypi/libtaxii/
21 | .. |downloads badge| image:: https://img.shields.io/pypi/dm/libtaxii.svg?maxAge=3600
22 | :target: https://pypi.python.org/pypi/libtaxii/
23 |
24 | Overview
25 | --------
26 |
27 | A primary goal of libtaxii is to remain faithful to both the TAXII
28 | specifications and to customary Python practices. libtaxii is designed to be
29 | intuitive both to Python developers and XML developers.
30 |
31 |
32 | Installation
33 | ------------
34 |
35 | Use pip to install or upgrade libtaxii::
36 |
37 | $ pip install libtaxii [--upgrade]
38 |
39 | For more information, see the `Installation instructions
40 | `_.
41 |
42 |
43 | Getting Started
44 | ---------------
45 |
46 | Read the `Getting Started guide
47 | `_.
48 |
49 |
50 | Layout
51 | ------
52 |
53 | The libtaxii repository has the following layout:
54 |
55 | * ``docs/`` - Used to build the `documentation
56 | `_.
57 | * ``libtaxii/`` - The main libtaxii source.
58 | * ``libtaxii/tests/`` - libtaxii tests.
59 | * ``xsd/`` - A copy of the TAXII XML Schemas, used by libtaxii for validation.
60 |
61 |
62 | Versioning
63 | ----------
64 |
65 | Releases of libtaxii are given ``major.minor.revision`` version numbers, where
66 | ``major`` and ``minor`` correspond to the TAXII version being supported. The
67 | ``revision``` number is used to indicate new versions of libtaxii.
68 |
69 |
70 | Feedback
71 | --------
72 |
73 | Please provide feedback and/or comments on open issues to taxii@mitre.org.
74 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | PAPER =
8 | BUILDDIR = _build
9 |
10 | # User-friendly check for sphinx-build
11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
13 | endif
14 |
15 | # Internal variables.
16 | PAPEROPT_a4 = -D latex_paper_size=a4
17 | PAPEROPT_letter = -D latex_paper_size=letter
18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
19 | # the i18n builder cannot share the environment and doctrees with the others
20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
21 |
22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
23 |
24 | help:
25 | @echo "Please use \`make ' where is one of"
26 | @echo " html to make standalone HTML files"
27 | @echo " dirhtml to make HTML files named index.html in directories"
28 | @echo " singlehtml to make a single large HTML file"
29 | @echo " pickle to make pickle files"
30 | @echo " json to make JSON files"
31 | @echo " htmlhelp to make HTML files and a HTML help project"
32 | @echo " qthelp to make HTML files and a qthelp project"
33 | @echo " devhelp to make HTML files and a Devhelp project"
34 | @echo " epub to make an epub"
35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
36 | @echo " latexpdf to make LaTeX files and run them through pdflatex"
37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
38 | @echo " text to make text files"
39 | @echo " man to make manual pages"
40 | @echo " texinfo to make Texinfo files"
41 | @echo " info to make Texinfo files and run them through makeinfo"
42 | @echo " gettext to make PO message catalogs"
43 | @echo " changes to make an overview of all changed/added/deprecated items"
44 | @echo " xml to make Docutils-native XML files"
45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes"
46 | @echo " linkcheck to check all external links for integrity"
47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)"
48 |
49 | clean:
50 | rm -rf $(BUILDDIR)/*
51 |
52 | html:
53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
54 | @echo
55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
56 |
57 | dirhtml:
58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
59 | @echo
60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
61 |
62 | singlehtml:
63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
64 | @echo
65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
66 |
67 | pickle:
68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
69 | @echo
70 | @echo "Build finished; now you can process the pickle files."
71 |
72 | json:
73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
74 | @echo
75 | @echo "Build finished; now you can process the JSON files."
76 |
77 | htmlhelp:
78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
79 | @echo
80 | @echo "Build finished; now you can run HTML Help Workshop with the" \
81 | ".hhp project file in $(BUILDDIR)/htmlhelp."
82 |
83 | qthelp:
84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
85 | @echo
86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \
87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/libtaxii.qhcp"
89 | @echo "To view the help file:"
90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/libtaxii.qhc"
91 |
92 | devhelp:
93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
94 | @echo
95 | @echo "Build finished."
96 | @echo "To view the help file:"
97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/libtaxii"
98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/libtaxii"
99 | @echo "# devhelp"
100 |
101 | epub:
102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
103 | @echo
104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
105 |
106 | latex:
107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
108 | @echo
109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \
111 | "(use \`make latexpdf' here to do that automatically)."
112 |
113 | latexpdf:
114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
115 | @echo "Running LaTeX files through pdflatex..."
116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf
117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
118 |
119 | latexpdfja:
120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
121 | @echo "Running LaTeX files through platex and dvipdfmx..."
122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
124 |
125 | text:
126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
127 | @echo
128 | @echo "Build finished. The text files are in $(BUILDDIR)/text."
129 |
130 | man:
131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
132 | @echo
133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
134 |
135 | texinfo:
136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
137 | @echo
138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
139 | @echo "Run \`make' in that directory to run these through makeinfo" \
140 | "(use \`make info' here to do that automatically)."
141 |
142 | info:
143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
144 | @echo "Running Texinfo files through makeinfo..."
145 | make -C $(BUILDDIR)/texinfo info
146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
147 |
148 | gettext:
149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
150 | @echo
151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
152 |
153 | changes:
154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
155 | @echo
156 | @echo "The overview file is in $(BUILDDIR)/changes."
157 |
158 | linkcheck:
159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
160 | @echo
161 | @echo "Link check complete; look for any errors in the above output " \
162 | "or in $(BUILDDIR)/linkcheck/output.txt."
163 |
164 | doctest:
165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
166 | @echo "Testing of doctests in the sources finished, look at the " \
167 | "results in $(BUILDDIR)/doctest/output.txt."
168 |
169 | xml:
170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
171 | @echo
172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
173 |
174 | pseudoxml:
175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
176 | @echo
177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
178 |
--------------------------------------------------------------------------------
/docs/api/clients.rst:
--------------------------------------------------------------------------------
1 | clients Module
2 | ==============
3 |
4 | .. module:: libtaxii.clients
5 |
6 |
7 | Classes
8 | -------
9 |
10 | .. autoclass:: libtaxii.clients.HttpClient
11 | :members: set_auth_type, set_auth_credentials, set_proxy, set_use_https,
12 | set_verify_server, call_taxii_service2
13 |
14 |
15 | Examples
16 | --------
17 |
18 | TAXII clients have three types of authentication credentials: None, HTTP Basic, and TLS Certificate. This section demonstrates usage of all three auth types.
19 |
20 | All examples assume the following imports:
21 |
22 | .. code-block:: python
23 |
24 | import libtaxii as t
25 | import libtaxii.messages_11 as tm11
26 | import libtaxii.clients as tc
27 | from libtaxii.common import generate_message_id
28 | from libtaxii.constants import *
29 | from dateutil.tz import tzutc
30 |
31 | Using No Credentials
32 | ********************
33 |
34 | .. code-block:: python
35 |
36 | client = tc.HttpClient()
37 | client.set_auth_type(tc.HttpClient.AUTH_NONE)
38 | client.set_use_https(False)
39 |
40 | discovery_request = tm11.DiscoveryRequest(generate_message_id())
41 | discovery_xml = discovery_request.to_xml(pretty_print=True)
42 |
43 | http_resp = client.call_taxii_service2('hailataxii.com', '/taxii-discovery-service', VID_TAXII_XML_11, discovery_xml)
44 | taxii_message = t.get_message_from_http_response(http_resp, discovery_request.message_id)
45 | print taxii_message.to_xml(pretty_print=True)
46 |
47 | Using Basic HTTP Auth
48 | *********************
49 |
50 | .. code-block:: python
51 |
52 | client = tc.HttpClient()
53 | client.set_auth_type(tc.HttpClient.AUTH_BASIC)
54 | client.set_auth_credentials({'username': 'guest', 'password': 'guest'})
55 |
56 | discovery_request = tm11.DiscoveryRequest(generate_message_id())
57 | discovery_xml = discovery_request.to_xml(pretty_print=True)
58 |
59 | http_resp = client.call_taxii_service2('hailataxii.com', '/taxii-discovery-service', VID_TAXII_XML_11, discovery_xml)
60 | taxii_message = t.get_message_from_http_response(http_resp, discovery_request.message_id)
61 | print taxii_message.to_xml(pretty_print=True)
62 |
63 | Using TLS Certificate Auth
64 | **************************
65 |
66 | Note: The following code is provided as an example of this authentication method, but will not work as-is, because Hail A Taxii does not support TLS.
67 |
68 | .. code-block:: python
69 |
70 | client = tc.HttpClient()
71 | client.set_use_https(True)
72 | client.set_auth_type(tc.HttpClient.AUTH_CERT)
73 | client.set_auth_credentials({'key_file': '../PATH_TO_KEY_FILE.key', 'cert_file': '../PATH_TO_CERT_FILE.crt'})
74 |
75 | discovery_request = tm11.DiscoveryRequest(generate_message_id())
76 | discovery_xml = discovery_request.to_xml(pretty_print=True)
77 |
78 | http_resp = client.call_taxii_service2('hailataxii.com', '/taxii-discovery-service/', VID_TAXII_XML_11, discovery_xml)
79 | taxii_message = t.get_message_from_http_response(http_resp, discovery_request.message_id)
80 | print taxii_message.to_xml(pretty_print=True)
81 |
--------------------------------------------------------------------------------
/docs/api/common.rst:
--------------------------------------------------------------------------------
1 | common Module
2 | =============
3 |
4 | .. automodule:: libtaxii.common
5 |
6 |
7 | Functions
8 | ---------
9 | .. autofunction:: get_xml_parser
10 | .. autofunction:: set_xml_parser
11 |
12 | Classes
13 | -------
14 |
15 | .. autoclass:: TAXIIBase
16 | :members:
17 |
--------------------------------------------------------------------------------
/docs/api/constants.rst:
--------------------------------------------------------------------------------
1 | constants Module
2 | ================
3 |
4 | .. module:: libtaxii.constants
5 |
6 | Constants
7 | ---------
8 |
9 | Version IDs
10 | ***********
11 |
12 | The following constants can be used as TAXII Version IDs
13 |
14 | .. autodata:: VID_TAXII_SERVICES_10
15 | .. autodata:: VID_TAXII_SERVICES_11
16 | .. autodata:: VID_TAXII_XML_10
17 | .. autodata:: VID_TAXII_XML_11
18 | .. autodata:: VID_TAXII_HTTP_10
19 | .. autodata:: VID_TAXII_HTTPS_10
20 |
21 | The following are third-party Version IDs included in libtaxii for convenience.
22 |
23 | .. autodata:: VID_CERT_EU_JSON_10
24 |
25 |
26 | Content Binding IDs
27 | *******************
28 |
29 | The following constants should be used as the Content Binding ID for STIX XML.
30 |
31 | .. autodata:: CB_STIX_XML_10
32 | .. autodata:: CB_STIX_XML_101
33 | .. autodata:: CB_STIX_XML_11
34 | .. autodata:: CB_STIX_XML_111
35 | .. autodata:: CB_STIX_XML_12
36 |
37 | These other Content Binding IDs are included for convenience as well.
38 |
39 | .. autodata:: CB_CAP_11
40 | .. autodata:: CB_XENC_122002
41 | .. autodata:: CB_SMIME
42 |
43 | Namespace Map
44 | *************
45 | This constant contains commonly namespaces and aliases in TAXII.
46 |
47 | .. autodata:: NS_MAP
48 |
49 | Message Types
50 | *************
51 |
52 | .. autodata:: MSG_STATUS_MESSAGE
53 | .. autodata:: MSG_DISCOVERY_REQUEST
54 | .. autodata:: MSG_DISCOVERY_RESPONSE
55 | .. autodata:: MSG_FEED_INFORMATION_REQUEST
56 | .. autodata:: MSG_FEED_INFORMATION_RESPONSE
57 | .. autodata:: MSG_MANAGE_FEED_SUBSCRIPTION_REQUEST
58 | .. autodata:: MSG_MANAGE_FEED_SUBSCRIPTION_RESPONSE
59 | .. autodata:: MSG_POLL_REQUEST
60 | .. autodata:: MSG_POLL_RESPONSE
61 | .. autodata:: MSG_INBOX_MESSAGE
62 |
63 | .. autodata:: MSG_TYPES_10
64 |
65 | .. autodata:: MSG_POLL_FULFILLMENT_REQUEST
66 | .. autodata:: MSG_COLLECTION_INFORMATION_REQUEST
67 | .. autodata:: MSG_COLLECTION_INFORMATION_RESPONSE
68 | .. autodata:: MSG_MANAGE_COLLECTION_SUBSCRIPTION_REQUEST
69 | .. autodata:: MSG_MANAGE_COLLECTION_SUBSCRIPTION_RESPONSE
70 |
71 | .. autodata:: MSG_TYPES_11
72 |
73 |
74 | Status Types
75 | ************
76 |
77 | These constants are used in :py:class:`StatusMessage`.
78 |
79 | .. autodata:: ST_BAD_MESSAGE
80 | .. autodata:: ST_DENIED
81 | .. autodata:: ST_FAILURE
82 | .. autodata:: ST_NOT_FOUND
83 | .. autodata:: ST_POLLING_UNSUPPORTED
84 | .. autodata:: ST_RETRY
85 | .. autodata:: ST_SUCCESS
86 | .. autodata:: ST_UNAUTHORIZED
87 | .. autodata:: ST_UNSUPPORTED_MESSAGE_BINDING
88 | .. autodata:: ST_UNSUPPORTED_CONTENT_BINDING
89 | .. autodata:: ST_UNSUPPORTED_PROTOCOL
90 |
91 | .. autodata:: ST_TYPES_10
92 |
93 | .. autodata:: ST_ASYNCHRONOUS_POLL_ERROR
94 | .. autodata:: ST_DESTINATION_COLLECTION_ERROR
95 | .. autodata:: ST_INVALID_RESPONSE_PART
96 | .. autodata:: ST_NETWORK_ERROR
97 | .. autodata:: ST_PENDING
98 | .. autodata:: ST_UNSUPPORTED_QUERY
99 |
100 | .. autodata:: ST_TYPES_11
101 |
102 |
103 | Subscription Actions
104 | ********************
105 |
106 | These constants are used in :py:class:`ManageFeedSubscriptionRequest`
107 |
108 | .. autodata:: ACT_SUBSCRIBE
109 | .. autodata:: ACT_UNSUBSCRIBE
110 | .. autodata:: ACT_STATUS
111 |
112 | .. autodata:: ACT_TYPES_10
113 |
114 | .. autodata:: ACT_PAUSE
115 | .. autodata:: ACT_RESUME
116 |
117 | .. autodata:: ACT_TYPES_11
118 |
119 |
120 | Service Types
121 | ****************
122 |
123 | These constants are used to indicate the type of service.
124 |
125 | .. autodata:: SVC_INBOX
126 | .. autodata:: SVC_POLL
127 | .. autodata:: SVC_FEED_MANAGEMENT
128 | .. autodata:: SVC_DISCOVERY
129 |
130 | .. autodata:: SVC_TYPES_10
131 |
132 | .. autodata:: SVC_COLLECTION_MANAGEMENT
133 |
134 | .. autodata:: SVC_TYPES_11
135 |
136 | Subscription Statuses
137 | *********************
138 |
139 | These constants are used in :py:class:`ManageCollectionSubscriptionResponse`
140 |
141 | .. autodata:: SS_ACTIVE
142 | .. autodata:: SS_PAUSED
143 | .. autodata:: SS_UNSUBSCRIBED
144 |
145 | .. autodata:: SS_TYPES_11
146 |
147 |
148 | Response Types
149 | **************
150 |
151 | These constants are used to indicate the type of response returned.
152 |
153 | .. autodata:: RT_FULL
154 | .. autodata:: RT_COUNT_ONLY
155 |
156 | .. autodata:: RT_TYPES_11
157 |
158 |
159 | Collection Types
160 | ****************
161 |
162 | These constants are used to indicate the type of collection.
163 |
164 | .. autodata:: CT_DATA_FEED
165 | .. autodata:: CT_DATA_SET
166 |
167 | .. autodata:: CT_TYPES_11
168 |
169 | Status Details
170 | **************
171 |
172 | These constants are used in :py:class:`StatusMessage`.
173 |
174 | .. autodata:: SD_ACCEPTABLE_DESTINATION
175 | .. autodata:: SD_MAX_PART_NUMBER
176 | .. autodata:: SD_ITEM
177 | .. autodata:: SD_ESTIMATED_WAIT
178 | .. autodata:: SD_RESULT_ID
179 | .. autodata:: SD_WILL_PUSH
180 | .. autodata:: SD_SUPPORTED_BINDING
181 | .. autodata:: SD_SUPPORTED_CONTENT
182 | .. autodata:: SD_SUPPORTED_PROTOCOL
183 | .. autodata:: SD_SUPPORTED_QUERY
184 |
185 | .. autodata:: SD_TYPES_11
186 |
187 | .. autodata:: SD_CAPABILITY_MODULE
188 | .. autodata:: SD_PREFERRED_SCOPE
189 | .. autodata:: SD_ALLOWED_SCOPE
190 | .. autodata:: SD_TARGETING_EXPRESSION_ID
191 |
192 | Query Formats
193 | *************
194 |
195 | These constants are used to indicate query format.
196 |
197 | ..autodata:: FID_TAXII_DEFAULT_QUERY_10
198 |
199 | Query Capability Modules
200 | ************************
201 |
202 | These constants are used to indicate TAXII Default Query Capability Modules
203 |
204 | .. autodata:: CM_CORE
205 | .. autodata:: CM_REGEX
206 | .. autodata:: CM_TIMESTAMP
207 |
208 | .. autodata:: CM_IDS
209 |
210 | Query Operators
211 | ***************
212 |
213 | These constants are used to identify the operator in :py:class`Criteria`
214 |
215 | .. autodata:: OP_OR
216 | .. autodata:: OP_AND
217 |
218 | .. autodata:: OP_TYPES
219 |
220 | Query Status Types
221 | ******************
222 |
223 | TAXII Default Query 1.0 identifies three additional Status Types:
224 |
225 | .. autodata:: ST_UNSUPPORTED_CAPABILITY_MODULE
226 | .. autodata:: ST_UNSUPPORTED_TARGETING_EXPRESSION
227 | .. autodata:: ST_UNSUPPORTED_TARGETING_EXPRESSION_ID
228 |
229 |
230 | Query Parameters
231 | ****************
232 |
233 | These constants are used to identify parameters.
234 |
235 | .. autodata:: P_VALUE
236 | .. autodata:: P_MATCH_TYPE
237 | .. autodata:: P_CASE_SENSITIVE
238 |
239 | .. autodata:: P_NAMES
240 |
241 | Query Relationships
242 | *******************
243 |
244 | These constants are used to identify relationships
245 |
246 | .. autodata:: R_EQUALS
247 | .. autodata:: R_NOT_EQUALS
248 | .. autodata:: R_GREATER_THAN
249 | .. autodata:: R_GREATER_THAN_OR_EQUAL
250 | .. autodata:: R_LESS_THAN
251 | .. autodata:: R_LESS_THAN_OR_EQUAL
252 | .. autodata:: R_DOES_NOT_EXIST
253 | .. autodata:: R_EXISTS
254 | .. autodata:: R_BEGINS_WITH
255 | .. autodata:: R_ENDS_WITH
256 | .. autodata:: R_CONTAINS
257 | .. autodata:: R_MATCHES
258 |
259 | .. autodata:: R_NAMES
260 |
--------------------------------------------------------------------------------
/docs/api/libtaxii.rst:
--------------------------------------------------------------------------------
1 | libtaxii Module
2 | ===============
3 |
4 | .. module:: libtaxii
5 |
6 | Functions
7 | ---------
8 |
9 | .. autofunction:: get_message_from_http_response
10 |
--------------------------------------------------------------------------------
/docs/api/messages_10.rst:
--------------------------------------------------------------------------------
1 | messages_10 Module
2 | ==================
3 |
4 | .. automodule:: libtaxii.messages_10
5 |
6 | .. note::
7 |
8 | The examples on this page assume that you have run the equivalent of
9 |
10 | .. code-block:: python
11 |
12 | import datetime
13 | from dateutil.tz import tzutc
14 | import libtaxii as t
15 | import libtaxii.messages_10 as tm10
16 | from libtaxii.constants import *
17 |
18 | .. testsetup::
19 |
20 | import datetime
21 | from dateutil.tz import tzutc
22 | import libtaxii as t
23 | import libtaxii.messages_10 as tm10
24 | from libtaxii.constants import *
25 |
26 | Status Message
27 | --------------
28 |
29 | .. autoclass:: StatusMessage
30 |
31 | **Example:**
32 |
33 | .. testcode::
34 |
35 | status_message1 = tm10.StatusMessage(
36 | message_id=tm10.generate_message_id(),
37 | in_response_to="12345",
38 | status_type=ST_SUCCESS,
39 | status_detail='Machine-processable info here!',
40 | message='This is a message.')
41 |
42 |
43 | Discovery Request
44 | -----------------
45 |
46 | .. autoclass:: DiscoveryRequest
47 |
48 | **Example:**
49 |
50 | .. testcode::
51 |
52 | ext_headers = {'name1': 'val1', 'name2': 'val2'}
53 | discovery_request = tm10.DiscoveryRequest(
54 | message_id=tm10.generate_message_id(),
55 | extended_headers=ext_headers)
56 |
57 |
58 | Discovery Response
59 | ------------------
60 |
61 | .. autoclass:: DiscoveryResponse
62 | .. autoclass:: ServiceInstance
63 |
64 | **Example:**
65 |
66 | .. testcode::
67 |
68 | discovery_response = tm10.DiscoveryResponse(
69 | message_id=tm10.generate_message_id(),
70 | in_response_to=discovery_request.message_id)
71 |
72 | service_instance = tm10.ServiceInstance(
73 | service_type=SVC_INBOX,
74 | services_version=VID_TAXII_SERVICES_10,
75 | protocol_binding=VID_TAXII_HTTPS_10,
76 | service_address='https://example.com/inbox/',
77 | message_bindings=[VID_TAXII_XML_10],
78 | inbox_service_accepted_content=[CB_STIX_XML_10],
79 | available=True,
80 | message='This is a sample inbox service instance')
81 |
82 | discovery_response.service_instances.append(service_instance)
83 |
84 | # Alternatively, you could define the service instance(s) first and use the
85 | # following:
86 |
87 | service_instance_list = [service_instance]
88 | discovery_response = tm10.DiscoveryResponse(
89 | message_id=tm10.generate_message_id(),
90 | in_response_to=discovery_request.message_id,
91 | service_instances=service_instance_list)
92 |
93 |
94 | Feed Information Request
95 | ------------------------
96 |
97 | .. autoclass:: FeedInformationRequest
98 |
99 | **Example:**
100 |
101 | .. testcode::
102 |
103 | ext_headers = {'name1': 'val1', 'name2': 'val2'}
104 | feed_information_request= tm10.FeedInformationRequest(
105 | message_id=tm10.generate_message_id(),
106 | extended_headers=ext_headers)
107 |
108 |
109 | Feed Information Response
110 | -------------------------
111 |
112 | .. autoclass:: FeedInformationResponse
113 | .. autoclass:: FeedInformation
114 | .. autoclass:: PushMethod
115 | .. autoclass:: PollingServiceInstance
116 | .. autoclass:: SubscriptionMethod
117 |
118 | **Example:**
119 |
120 | .. testcode::
121 |
122 | push_method1 = tm10.PushMethod(
123 | push_protocol=VID_TAXII_HTTP_10,
124 | push_message_bindings=[VID_TAXII_XML_10])
125 |
126 | polling_service1 = tm10.PollingServiceInstance(
127 | poll_protocol=VID_TAXII_HTTP_10,
128 | poll_address='http://example.com/PollService/',
129 | poll_message_bindings=[VID_TAXII_XML_10])
130 |
131 | subscription_service1 = tm10.SubscriptionMethod(
132 | subscription_protocol=VID_TAXII_HTTP_10,
133 | subscription_address='http://example.com/SubsService/',
134 | subscription_message_bindings=[VID_TAXII_XML_10])
135 |
136 | feed1 = tm10.FeedInformation(
137 | feed_name='Feed1',
138 | feed_description='Description of a feed',
139 | supported_contents=[CB_STIX_XML_10],
140 | available=True,
141 | push_methods=[push_method1],
142 | polling_service_instances=[polling_service1],
143 | subscription_methods=[subscription_service1])
144 |
145 | feed_information_response1 = tm10.FeedInformationResponse(
146 | message_id=tm10.generate_message_id(),
147 | in_response_to=tm10.generate_message_id(),
148 | feed_informations=[feed1])
149 |
150 |
151 | Manage Feed Subscription Request
152 | --------------------------------
153 |
154 | .. autoclass:: ManageFeedSubscriptionRequest
155 |
156 | **Example:**
157 |
158 | .. testcode::
159 |
160 | delivery_parameters1 = tm10.DeliveryParameters(
161 | inbox_protocol=VID_TAXII_HTTP_10,
162 | inbox_address='http://example.com/inbox',
163 | delivery_message_binding=VID_TAXII_XML_10,
164 | content_bindings=[CB_STIX_XML_10])
165 |
166 | manage_feed_subscription_request1 = tm10.ManageFeedSubscriptionRequest(
167 | message_id=tm10.generate_message_id(),
168 | feed_name='SomeFeedName',
169 | action=ACT_UNSUBSCRIBE,
170 | subscription_id='SubsId056',
171 | delivery_parameters=delivery_parameters1)
172 |
173 |
174 | Manage Feed Subscription Response
175 | ---------------------------------
176 |
177 | .. autoclass:: ManageFeedSubscriptionResponse
178 | .. autoclass:: SubscriptionInstance
179 | .. autoclass:: PollInstance
180 |
181 | **Example:**
182 |
183 | .. testcode::
184 |
185 | poll_instance1 = tm10.PollInstance(
186 | poll_protocol=VID_TAXII_HTTP_10,
187 | poll_address='http://example.com/poll',
188 | poll_message_bindings=[VID_TAXII_XML_10])
189 |
190 | subscription_instance1 = tm10.SubscriptionInstance(
191 | subscription_id='SubsId234',
192 | delivery_parameters=[delivery_parameters1],
193 | poll_instances=[poll_instance1])
194 |
195 | manage_feed_subscription_response1 = tm10.ManageFeedSubscriptionResponse(
196 | message_id=tm10.generate_message_id(),
197 | in_response_to="12345",
198 | feed_name='Feed001',
199 | message='This is a message',
200 | subscription_instances=[subscription_instance1])
201 |
202 |
203 | Poll Request
204 | ------------
205 |
206 | .. autoclass:: PollRequest
207 |
208 | **Example:**
209 |
210 | .. testcode::
211 |
212 | poll_request1 = tm10.PollRequest(
213 | message_id=tm10.generate_message_id(),
214 | feed_name='TheFeedToPoll',
215 | exclusive_begin_timestamp_label=datetime.datetime.now(tzutc()),
216 | inclusive_end_timestamp_label=datetime.datetime.now(tzutc()),
217 | subscription_id='SubsId002',
218 | content_bindings=[CB_STIX_XML_10])
219 |
220 |
221 | Poll Response
222 | -------------
223 |
224 | .. autoclass:: PollResponse
225 |
226 | **Example:**
227 |
228 | .. testcode::
229 |
230 | poll_response1 = tm10.PollResponse(
231 | message_id=tm10.generate_message_id(),
232 | in_response_to="12345",
233 | feed_name='FeedName',
234 | inclusive_begin_timestamp_label=datetime.datetime.now(tzutc()),
235 | inclusive_end_timestamp_label=datetime.datetime.now(tzutc()),
236 | subscription_id='SubsId001',
237 | message='This is a message.',
238 | content_blocks=[])
239 |
240 |
241 | Inbox Message
242 | -------------
243 |
244 | .. autoclass:: InboxMessage
245 | .. autoclass:: SubscriptionInformation
246 |
247 | **Example:**
248 |
249 | .. testcode::
250 |
251 | cb1 = tm10.ContentBlock(CB_STIX_XML_11, "")
252 |
253 | subscription_information1 = tm10.SubscriptionInformation(
254 | feed_name='SomeFeedName',
255 | subscription_id='SubsId021',
256 | inclusive_begin_timestamp_label=datetime.datetime.now(tzutc()),
257 | inclusive_end_timestamp_label=datetime.datetime.now(tzutc()))
258 |
259 | inbox_message1 = tm10.InboxMessage(
260 | message_id=tm10.generate_message_id(),
261 | message='This is a message.',
262 | subscription_information=subscription_information1,
263 | content_blocks=[cb1])
264 |
265 |
266 | Other Classes
267 | -------------
268 |
269 | .. autoclass:: TAXIIMessage
270 |
271 | .. autoclass:: ContentBlock
272 |
273 | **Example:**
274 |
275 | .. testcode::
276 |
277 | cb1 = tm10.ContentBlock(
278 | content_binding=CB_STIX_XML_10,
279 | content='')
280 |
281 | .. autoclass:: DeliveryParameters
282 |
283 |
284 | Functions
285 | ---------
286 |
287 | .. autofunction:: generate_message_id
288 | .. autofunction:: validate_xml
289 | .. autofunction:: get_message_from_xml
290 | .. autofunction:: get_message_from_dict
291 | .. autofunction:: get_message_from_json
292 |
293 |
--------------------------------------------------------------------------------
/docs/api/messages_11.rst:
--------------------------------------------------------------------------------
1 | messages_11 Module
2 | ==================
3 |
4 | .. automodule:: libtaxii.messages_11
5 |
6 | .. note::
7 |
8 | The examples on this page assume that you have run the equivalent of
9 |
10 | .. code-block:: python
11 |
12 | import datetime
13 | from dateutil.tz import tzutc
14 | import libtaxii as t
15 | import libtaxii.messages_11 as tm11
16 | from libtaxii.constants import *
17 |
18 | .. testsetup::
19 |
20 | import datetime
21 | from dateutil.tz import tzutc
22 | import libtaxii as t
23 | import libtaxii.messages_11 as tm11
24 | from libtaxii.constants import *
25 |
26 | Status Message
27 | --------------
28 |
29 | .. autoclass:: StatusMessage
30 |
31 | **Example:**
32 |
33 | .. testcode::
34 |
35 | sm03 = tm11.StatusMessage(
36 | message_id='SM03',
37 | in_response_to=tm11.generate_message_id(),
38 | status_type=ST_DESTINATION_COLLECTION_ERROR,
39 | status_detail={'ACCEPTABLE_DESTINATION': ['Collection1','Collection2']})
40 |
41 |
42 | Discovery Request
43 | -----------------
44 |
45 | .. autoclass:: DiscoveryRequest
46 |
47 | **Example:**
48 |
49 | .. testcode::
50 |
51 | headers={'ext_header1': 'value1', 'ext_header2': 'value2'}
52 | discovery_request = tm11.DiscoveryRequest(
53 | message_id=tm11.generate_message_id(),
54 | extended_headers=headers)
55 |
56 |
57 | Discovery Response
58 | ------------------
59 |
60 | .. autoclass:: DiscoveryResponse
61 | .. autoclass:: ServiceInstance
62 |
63 | **Example:**
64 |
65 | .. testcode::
66 |
67 | discovery_response = tm11.DiscoveryResponse(
68 | message_id=tm11.generate_message_id(),
69 | in_response_to=discovery_request.message_id)
70 |
71 | service_instance = tm11.ServiceInstance(
72 | service_type=SVC_POLL,
73 | services_version=VID_TAXII_SERVICES_11,
74 | protocol_binding=VID_TAXII_HTTP_10,
75 | service_address='http://example.com/poll/',
76 | message_bindings=[VID_TAXII_XML_11],
77 | available=True,
78 | message='This is a message.',
79 | #supported_query=[tdq1],
80 | )
81 |
82 | discovery_response.service_instances.append(service_instance)
83 |
84 | # Alternatively, you could define the service instance(s) first and use the
85 | # following:
86 |
87 | service_instance_list = [service_instance]
88 | discovery_response = tm11.DiscoveryResponse(
89 | message_id=tm11.generate_message_id(),
90 | in_response_to=discovery_request.message_id,
91 | service_instances=service_instance_list)
92 |
93 |
94 | Collection Information Request
95 | ------------------------------
96 |
97 | .. autoclass:: CollectionInformationRequest
98 |
99 | **Example:**
100 |
101 | .. testcode::
102 |
103 | ext_headers = {'name1': 'val1', 'name2': 'val2'}
104 | collection_information_request = tm11.CollectionInformationRequest(
105 | message_id='CIReq01',
106 | extended_headers=ext_headers)
107 |
108 |
109 | Collection Information Response
110 | -------------------------------
111 |
112 | .. autoclass:: CollectionInformationResponse
113 | .. autoclass:: CollectionInformation
114 | .. autoclass:: PushMethod
115 | .. autoclass:: PollingServiceInstance
116 | .. autoclass:: SubscriptionMethod
117 | .. autoclass:: ReceivingInboxService
118 |
119 | **Example:**
120 |
121 | .. testcode::
122 |
123 | push_method1 = tm11.PushMethod(
124 | push_protocol=VID_TAXII_HTTP_10,
125 | push_message_bindings=[VID_TAXII_XML_11])
126 |
127 | poll_service1 = tm11.PollingServiceInstance(
128 | poll_protocol=VID_TAXII_HTTPS_10,
129 | poll_address='https://example.com/PollService1',
130 | poll_message_bindings=[VID_TAXII_XML_11])
131 |
132 | poll_service2 = tm11.PollingServiceInstance(
133 | poll_protocol=VID_TAXII_HTTPS_10,
134 | poll_address='https://example.com/PollService2',
135 | poll_message_bindings=[VID_TAXII_XML_11])
136 |
137 | subs_method1 = tm11.SubscriptionMethod(
138 | subscription_protocol=VID_TAXII_HTTPS_10,
139 | subscription_address='https://example.com/SubscriptionService',
140 | subscription_message_bindings=[VID_TAXII_XML_11])
141 |
142 | inbox_service1 = tm11.ReceivingInboxService(
143 | inbox_protocol=VID_TAXII_HTTPS_10,
144 | inbox_address='https://example.com/InboxService',
145 | inbox_message_bindings=[VID_TAXII_XML_11],
146 | supported_contents=None)
147 |
148 | collection1 = tm11.CollectionInformation(
149 | collection_name='collection1',
150 | collection_description='This is a collection',
151 | supported_contents=[tm11.ContentBinding(CB_STIX_XML_101)],
152 | available=False,
153 | push_methods=[push_method1],
154 | polling_service_instances=[poll_service1, poll_service2],
155 | subscription_methods=[subs_method1],
156 | collection_volume=4,
157 | collection_type=CT_DATA_FEED,
158 | receiving_inbox_services=[inbox_service1])
159 |
160 | collection_response1 = tm11.CollectionInformationResponse(
161 | message_id='CIR01',
162 | in_response_to='0',
163 | collection_informations=[collection1])
164 |
165 |
166 | Manage Collection Subscription Request
167 | --------------------------------------
168 |
169 | .. autoclass:: ManageCollectionSubscriptionRequest
170 |
171 | **Example:**
172 |
173 | .. testcode::
174 |
175 | subscription_parameters1 = tm11.SubscriptionParameters()
176 | push_parameters1 = tm11.PushParameters("", "", "")
177 |
178 | subs_req1 = tm11.ManageCollectionSubscriptionRequest(
179 | message_id='SubsReq01',
180 | action=ACT_SUBSCRIBE,
181 | collection_name='collection1',
182 | subscription_parameters=subscription_parameters1,
183 | push_parameters=push_parameters1)
184 |
185 |
186 | Manage Collection Subscription Response
187 | ---------------------------------------
188 |
189 | .. autoclass:: ManageCollectionSubscriptionResponse
190 | .. autoclass:: SubscriptionInstance
191 | .. autoclass:: PollInstance
192 |
193 | **Example:**
194 |
195 | .. testcode::
196 |
197 | subscription_parameters1 = tm11.SubscriptionParameters()
198 | push_parameters1 = tm11.PushParameters("", "", "")
199 |
200 |
201 | poll_instance1 = tm11.PollInstance(
202 | poll_protocol=VID_TAXII_HTTPS_10,
203 | poll_address='https://example.com/poll1/',
204 | poll_message_bindings=[VID_TAXII_XML_11])
205 |
206 | subs1 = tm11.SubscriptionInstance(
207 | subscription_id='Subs001',
208 | status=SS_ACTIVE,
209 | subscription_parameters=subscription_parameters1,
210 | push_parameters=push_parameters1,
211 | poll_instances=[poll_instance1])
212 |
213 | subs_resp1 = tm11.ManageCollectionSubscriptionResponse(
214 | message_id='SubsResp01',
215 | in_response_to='xyz',
216 | collection_name='abc123',
217 | message='Hullo!',
218 | subscription_instances=[subs1])
219 |
220 |
221 | Poll Request
222 | ------------
223 |
224 | .. autoclass:: PollRequest
225 | .. autoclass:: PollParameters
226 |
227 | **Example:**
228 |
229 | .. testcode::
230 |
231 | delivery_parameters1 = tm11.DeliveryParameters(
232 | inbox_protocol=VID_TAXII_HTTPS_10,
233 | inbox_address='https://example.com/inboxAddress/',
234 | delivery_message_binding=VID_TAXII_XML_11)
235 |
236 | poll_params1 = tm11.PollParameters(
237 | allow_asynch=False,
238 | response_type=RT_COUNT_ONLY,
239 | content_bindings=[tm11.ContentBinding(binding_id=CB_STIX_XML_11)],
240 | #query=query1,
241 | delivery_parameters=delivery_parameters1)
242 |
243 | poll_req3 = tm11.PollRequest(
244 | message_id='PollReq03',
245 | collection_name='collection100',
246 | exclusive_begin_timestamp_label=datetime.datetime.now(tzutc()),
247 | inclusive_end_timestamp_label=datetime.datetime.now(tzutc()),
248 | poll_parameters=poll_params1)
249 |
250 |
251 | Poll Response
252 | -------------
253 |
254 | .. autoclass:: PollResponse
255 |
256 | **Example:**
257 |
258 | .. testcode::
259 |
260 | cb1 = tm11.ContentBlock(CB_STIX_XML_11, "")
261 | cb2 = tm11.ContentBlock(CB_STIX_XML_11, "")
262 |
263 | count = tm11.RecordCount(record_count=22, partial_count=False)
264 |
265 | poll_resp1 = tm11.PollResponse(
266 | message_id='PollResp1',
267 | in_response_to='tmp',
268 | collection_name='blah',
269 | exclusive_begin_timestamp_label=datetime.datetime.now(tzutc()),
270 | inclusive_end_timestamp_label=datetime.datetime.now(tzutc()),
271 | subscription_id='24',
272 | message='This is a test message',
273 | content_blocks=[cb1, cb2],
274 | more=True,
275 | result_id='123',
276 | result_part_number=1,
277 | record_count=count)
278 |
279 |
280 | Inbox Message
281 | -------------
282 |
283 | .. autoclass:: InboxMessage
284 | .. autoclass:: SubscriptionInformation
285 |
286 | **Example:**
287 |
288 | .. testcode::
289 |
290 | cb1 = tm11.ContentBlock(CB_STIX_XML_11, "")
291 | cb2 = tm11.ContentBlock(CB_STIX_XML_11, "")
292 |
293 | subs_info1 = tm11.SubscriptionInformation(
294 | collection_name='SomeCollectionName',
295 | subscription_id='SubsId021',
296 | exclusive_begin_timestamp_label=datetime.datetime.now(tzutc()),
297 | inclusive_end_timestamp_label=datetime.datetime.now(tzutc()))
298 |
299 | inbox1 = tm11.InboxMessage(
300 | message_id='Inbox1',
301 | result_id='123',
302 | destination_collection_names=['collection1','collection2'],
303 | message='Hello!',
304 | subscription_information=subs_info1,
305 | record_count=tm11.RecordCount(22, partial_count=True),
306 | content_blocks=[cb1, cb2])
307 |
308 |
309 | Poll Fulfillment Request
310 | ------------------------
311 |
312 | .. autoclass:: PollFulfillmentRequest
313 |
314 | **Example:**
315 |
316 | .. testcode::
317 |
318 | pf1 = tm11.PollFulfillmentRequest(
319 | message_id='pf1',
320 | collection_name='1-800-collection',
321 | result_id='123',
322 | result_part_number=1)
323 |
324 |
325 | Other Classes
326 | -------------
327 |
328 | .. autoclass:: TAXIIMessage
329 |
330 | .. autoclass:: ContentBinding
331 | .. autoclass:: ContentBlock
332 |
333 | **Example:**
334 |
335 | .. testcode::
336 |
337 | cb001 = tm11.ContentBlock(
338 | content_binding=tm11.ContentBinding(CB_STIX_XML_11),
339 | content='',
340 | timestamp_label=datetime.datetime.now(tzutc()),
341 | message='Hullo!',
342 | padding='The quick brown fox jumped over the lazy dogs.')
343 |
344 | .. autoclass:: DeliveryParameters
345 | .. autoclass:: PushParameters
346 | .. autoclass:: RecordCount
347 | .. autoclass:: SubscriptionParameters
348 |
349 |
350 | Functions
351 | ---------
352 |
353 | .. autofunction:: generate_message_id
354 | .. autofunction:: validate_xml
355 | .. autofunction:: get_message_from_xml
356 | .. autofunction:: get_message_from_dict
357 | .. autofunction:: get_message_from_json
358 |
--------------------------------------------------------------------------------
/docs/api/modules.rst:
--------------------------------------------------------------------------------
1 | .. _apidoc:
2 |
3 | API Documentation
4 | -----------------
5 |
6 | .. toctree::
7 |
8 | libtaxii
9 | common
10 | constants
11 | clients
12 | messages_10
13 | messages_11
14 | query
15 | validation
16 |
--------------------------------------------------------------------------------
/docs/api/query.rst:
--------------------------------------------------------------------------------
1 | taxii_default_query Module
2 | ==========================
3 |
4 | .. automodule:: libtaxii.taxii_default_query
5 |
6 | Classes
7 | -------
8 |
9 | Default Query
10 | *************
11 |
12 | .. autoclass:: DefaultQuery
13 | :show-inheritance:
14 | :members:
15 |
16 | **Example**
17 |
18 | .. code-block:: python
19 |
20 | import libtaxii.taxii_default_query as tdq
21 | from libtaxii.taxii_default_query import Test
22 | from libtaxii.taxii_default_query import Criterion
23 | from libtaxii.taxii_default_query import Criteria
24 | from libtaxii.constants import *
25 | import datetime
26 |
27 | ##############################################################################
28 | # A Taxii Default Query *Test* gives the consumer granular control over the
29 | # Target of a Query by applying unambiguos relationship requirements specified
30 | # using a standardized vocabulary.
31 |
32 | # Each Relationship (e.g. equals, matches, greater_than, etc.) in a Capability
33 | # Module defines a set of paramater fields, capable of expressing that
34 | # relation.
35 |
36 | # The *equals* relationship, of the Core Capability Module, returns True if
37 | # the target matches the value exactly. If the target merely contains the
38 | # value (but does not match exactly) the relationship Test returns False.
39 | test_equals = Test(capability_id=CM_CORE,
40 | relationship='equals',
41 | parameters={'value': 'Test value',
42 | 'match_type': 'case_sensitive_string'})
43 |
44 | # The *matches* relationship, in the context of the Regular Expression
45 | # Capability Module, returns true if the target matches the regular expression
46 | # contained in the value.
47 | test_matches = Test(capability_id=CM_REGEX,
48 | relationship='matches',
49 | parameters={'value': '[A-Z]*',
50 | 'case_sensitive': True})
51 |
52 | # The *greater than* relationship, in the context of the Timestamp Capability
53 | # Module returns True if the target's timestamp indicates a later time than
54 | # that specified by this value. This relationship is only valid for timestamp
55 | # comparisons.
56 | test_timestamp = Test(capability_id=CM_TIMESTAMP,
57 | relationship='greater_than',
58 | parameters={'value': datetime.datetime.now()})
59 |
60 |
61 | ##############################################################################
62 | # A *Criterion* specifies how a Target is evaluated against a Test. Within a
63 | # Criterion, the Target is used to identify a specific region of a record to
64 | # which the Test should be applied. Slash Notation Targeting Expression syntax,
65 | # in conjunction with a Targeting Expression Vocabulary, are used to form a
66 | # Targeting Expression
67 |
68 | # A Multi-field Wildcard (**). This indicates any Node or series of Nodes,
69 | # specified by double asterisks.
70 | criterion1 = Criterion(target='**',
71 | test=test_equals)
72 |
73 | # Indicates that *id* fields in the STIX Indicator construct are in scope
74 | criterion2 = Criterion(target='STIX_Package/Indicators/Indicator/@id',
75 | test=test_matches)
76 |
77 | # Indicates that all STIX Description fields are in scope
78 | criterion3 = Criterion(target='**/Description',
79 | test=test_timestamp)
80 |
81 |
82 | ##############################################################################
83 | # *Criteria* consist of a logical operator (and/or) that should be applied to
84 | # child Criteria and Criterion to determine whether content matches this query.
85 |
86 | criteria1 = Criteria(operator=OP_AND,
87 | criterion=[criterion1])
88 |
89 | criteria2 = Criteria(operator=OP_OR,
90 | criterion=[criterion1, criterion2, criterion3])
91 |
92 | criteria3 = Criteria(operator=OP_AND,
93 | criterion=[criterion1, criterion3],
94 | criteria=[criteria2])
95 |
96 |
97 | ##############################################################################
98 | # query1, query2 and query3 would be able to be used in TAXII requests that
99 | # contain queries (e.g., PollRequest Messages)
100 | query1 = tdq.DefaultQuery(targeting_expression_id=CB_STIX_XML_111,
101 | criteria=criteria1)
102 |
103 | query2 = tdq.DefaultQuery(targeting_expression_id=CB_STIX_XML_111,
104 | criteria=criteria3)
105 |
106 | query3 = tdq.DefaultQuery(targeting_expression_id=CB_STIX_XML_111,
107 | criteria=criteria2)
108 |
109 |
110 | Default Query Info
111 | ******************
112 |
113 | .. autoclass:: DefaultQueryInfo
114 | :show-inheritance:
115 | :members:
116 |
117 | **Example**
118 |
119 | .. code-block:: python
120 |
121 | import libtaxii.taxii_default_query as tdq
122 | from libtaxii.taxii_default_query import TargetingExpressionInfo
123 | from libtaxii.constants import *
124 |
125 | ##############################################################################
126 | # *TargetingExpressionInfo* describes which expressions are available to
127 | # a consumer when submitting a query to a taxii service. A
128 | # `targetting_expression_id` indicates a suppoted targetting vocabulary
129 | # TargetingExpressionInfo also contains the permissible scope of queries.
130 |
131 | # This example has no preferred scope, and allows any scope
132 | tei_01 = TargetingExpressionInfo(
133 | targeting_expression_id=CB_STIX_XML_111,
134 | preferred_scope=[],
135 | allowed_scope=['**'])
136 |
137 | # This example prefers the Indicator scope and allows no other scope
138 | tei_02 = TargetingExpressionInfo(
139 | targeting_expression_id=CB_STIX_XML_111,
140 | preferred_scope=['STIX_Package/Indicators/Indicator/**'],
141 | allowed_scope=[])
142 |
143 |
144 | ##############################################################################
145 | # *DefaultQueryInfo* describes the TAXII Default Queries that are supported
146 | # using a list of TargetExpressionInfo objects, and a list of capability
147 | # module identifiers.
148 | tdqi1 = tdq.DefaultQueryInfo(
149 | targeting_expression_infos=[tei_01, tei_02],
150 | capability_modules=[CM_CORE])
151 |
--------------------------------------------------------------------------------
/docs/api/validation.rst:
--------------------------------------------------------------------------------
1 | validation Module
2 | =================
3 |
4 | .. _apivalidation:
5 |
6 | .. currentmodule:: libtaxii.validation
7 |
8 | Validate TAXII Content
9 | ----------------------
10 |
11 | .. autoclass:: SchemaValidator
12 | :members:
13 | :exclude-members: TAXII_10_SCHEMA, TAXII_11_SCHEMA
14 | .. autodata:: TAXII_10_SCHEMA
15 | :annotation: Use TAXII 1.0 schema for validation.
16 | .. autodata:: TAXII_11_SCHEMA
17 | :annotation: Use TAXII 1.1 schema for validation.
18 | .. autoclass:: TAXII10Validator
19 | :show-inheritance:
20 | .. autoclass:: TAXII11Validator
21 | :show-inheritance:
22 |
23 |
--------------------------------------------------------------------------------
/docs/changes.rst:
--------------------------------------------------------------------------------
1 | Release Notes
2 | =============
3 |
4 | 1.1.119 (2021-04-15)
5 | --------------------
6 | `(diff) `__
7 |
8 | - #248 Writing content blocks should not be dependent on value of "more" (@brlogan)
9 |
10 |
11 | 1.1.118 (2020-10-19)
12 | --------------------
13 | `(diff) `__
14 |
15 | - #247 [CVE-2020-27197] Avoid SSRF on parsing XML (@orsinium)
16 |
17 |
18 | 1.1.117 (2020-05-26)
19 | --------------------
20 | `(diff) `__
21 |
22 | - #244 SSL Verify Server not working correctly (@motok) (@nschwane)
23 | - #245 Unicode `lxml.etree.SerialisationError` on lxml 4.5.0+ (@advptr)
24 |
25 |
26 | 1.1.116 (2020-02-14)
27 | --------------------
28 | `(diff) `__
29 |
30 | - #240 PY3 Compatibility changes for HTTP Response Body (@nschwane)
31 |
32 |
33 | 1.1.115 (2019-11-12)
34 | --------------------
35 | `(diff) `__
36 |
37 | - #239 Convert the HTTP response body to a string type (PY3 this will be bytes) (@sddj)
38 |
39 |
40 | 1.1.114 (2019-07-26)
41 | --------------------
42 | `(diff) `__
43 |
44 | - #237 Support converting dicts to content bindings (@danielsamuels)
45 | - #238 Provide XMLParser copies instead of reusing the cached instance. Prevents future messages to lose namespace
46 |
47 |
48 | 1.1.113 (2019-04-11)
49 | --------------------
50 | `(diff) `__
51 |
52 | - #234 Add ability to load a configuration file when executing a script
53 | - #232 Fix TLS handshake failure when a server requires SNI (@marcelslotema)
54 |
55 |
56 | 1.1.112 (2018-11-27)
57 | --------------------
58 | `(diff) `__
59 |
60 | - #227 Fixes to poll_client script (Python3 compatibility)
61 | - #226 Clean-up documentation warnings
62 | - #228 Fix 'HTTPMessage' has no attribute 'getheader' (Python3 compatibility)
63 | - #225 Fix checks that involve xpath (lxml) to prevent FutureWarning message
64 | - #230 Fix parsing status message round-trip (@danielsamuels)
65 |
66 |
67 | 1.1.111 (2017-06-07)
68 | --------------------
69 | `(diff) `__
70 |
71 | - Fix #222, #224 - Update clients.py to work with Python 2.6, 3.3, 3.5, and 3.6.
72 | - Fix #221 - Add Python 3.6 support.
73 | - Fix #219 - Handle Unicode- and byte-strings consistently.
74 | - Fix #214 - Add timeout parameter to call_taxii_service2 (@mbekavac)
75 | - Fix #192 - Add support for STIX 1.2.
76 | - Add user_agent parameter to call_taxii_service2 (@kralka)
77 |
78 |
79 | 1.1.110 (2016-09-08)
80 | --------------------
81 | `(diff) `__
82 |
83 | - Fix #210 - Use hailataxii.com in examples instead of taxiitest.mitre.org (@clenk)
84 | - Fix #183 - Update incorrect comment (@daybarr)
85 | - Fix SMIME Content Binding ID typo (@brlogan)
86 |
87 |
88 | 1.1.109 (2015-11-16)
89 | --------------------
90 | `(diff) `__
91 |
92 | - Fix #203 - Fix SSL context on older Python 2.7 versions (@traut)
93 |
94 |
95 | 1.1.108 (2015-10-29)
96 | --------------------
97 | `(diff) `__
98 |
99 | - Support password-protected SSL keys (@traut)
100 | - Fix #200 - Bad encodings no longer generate Exceptions (@MarkDavidson)
101 |
102 |
103 | 1.1.107 (2015-08-05)
104 | --------------------
105 | `(diff) `__
106 |
107 | - Fix #184 - Use proxy for both HTTP and HTTPS (@nadavc)
108 | - Fix #187 - Handle numeric values in taxii_default_query (@stkyle)
109 | - Update Example Query documentation (@stkyle)
110 | - Fix #189 - Update how constants are used and referenced (@stkyle)
111 | - Show HTTP error code in StatusMessage.message (@ahippo)
112 | - Python 3 compatibility (@rjprins)
113 |
114 |
115 | 1.1.106
116 | -------
117 | `(diff) `__
118 |
119 | - Thank you to the multiple contributors for this release: @traut, @gtback, @wbolster, and @MarkDavidson, and thank you to those who filed issues that were fixed in this release.
120 | - Timestamp labels can now be provided as a string or as a python datetime object. Previously, only datetime objects were permitted.
121 | - Some big changes to TAXII Client command line args. Deprecated URL components (e.g., --host, --port) in favor of specifying a single url (--url)
122 | - Added a TAXII Inbox 1.0 client
123 | - Decreased the likelihood of future message ID collisions
124 | - A variety of improvements in the following areas: data validation, typos, documentation, DRY-ness, overall repo quality (thanks @gtback)
125 | - Multiple code cleanup changes (Thanks in part to @traut of IntelWorks)
126 |
127 |
128 | 1.1.105
129 | -------
130 | `(diff) `__
131 |
132 | - Fixed multiple XML parsing related vulnerabilities (Thanks @guidovranken of IntelWorks for the vulnerability research!)
133 |
134 |
135 | 1.1.104
136 | -------
137 | `(diff) `__
138 |
139 | - Fixed a bug where libtaxii did not properly handle XML values for Extended Headers
140 | - Added checking for required status detail keys in Status Messages
141 | - Improved data validation in various places, fixed various bugs, and improved documentation
142 | - Improved filename generation in scripts (Thanks @guidovranken!)
143 |
144 |
145 | 1.1.103
146 | -------
147 | `(diff) `__
148 |
149 | In terms of code organization, there are a few big changes beginning to
150 | take place in this version of libtaxii. Constants and commonly used classes/functions
151 | are being moved to common locations (libtaxii.constants and libtaxii.common, respectively).
152 | Also, nested classes (e.g., messages_11.DiscoveryResponse.ServiceInstance) have been de-nested
153 | (e.g., is now messages_11.ServiceInstance). All of these changes are intended to make
154 | using libtaxii easier. For the time being, backward compatibility has been maintained, but
155 | many of these changes may result in a backward compatibility breaking change in a future,
156 | major release of libtaxii.
157 |
158 | Major changes:
159 |
160 | - libtaxii.constants, a new source file, was created. The definition for all constants in libtaxii have been moved to libtaxii.constants. Aliases to the previous definition locations have been retained for backward compatibility and may be removed in a future major release.
161 | - libtaxii.common, a new source file for containing classes and methods common to TAXII, was created. Some common classes and functions have been moved into libtaxii.common, and more will be moved over time. Aliases to the previous classes and functions have been retained for backward compatibility and may be removed in a future major release. (Thanks, @gtback!)
162 | - Promoted nested classes to module-level classes in messages_10, messages_11, and taxii_default_query. Aliases to the previous, nested, classes have been retained for backward compatibility and may be removed in a future major release. (Thanks, @gtback!)
163 | - A ‘to_text()’ method has been added to all TAXII Message classes. ‘to_text()’ provides a “nicely formatted” human readable representation of a TAXII Message and its components. The ‘to_text()’ method was added to support libtaxii’s scripts. There is no ‘from_text()’ method as this is not intended to be a serialization/deserialization feature, but a readability feature.
164 | - Lowered the required version of lxml to 2.2.3, the latest available on RHEL 6. (Thanks to @mblayman for raising this)
165 | - Lowered the required version of python-dateutil to 1.4.1, the latest available on RHEL 6. (Thanks to @mblayman for raising this)
166 | - TAXII 1.1 StatusMessages now raise a ValueError when required a Status Detail is not set.
167 | - TAXII XML Validation has a new methodology: See validation.SchemaValidator (http://libtaxii.readthedocs.org/en/latest/api/validation.html#libtaxii.validation.SchemaValidator)
168 | - Related: validate_xml(…) has been deprecated and may be removed in a future major release.
169 |
170 | Minor changes:
171 |
172 | - Tons of PEP8 improvements (Thanks, @gtback!)
173 | - TAXII Scripts have been entirely reorganized to be more DRY.
174 | - Added two constants for Proxy Settings (SYSTEM_PROXY and NO_PROXY). These supersede the need to use either None or ‘noproxy’, which were not as clear to developers.
175 | - Improved documentation, Tox usage, and Travis-CI usage. (Thanks, @gtback!)
176 | - SMIME Content Binding added (application/x-pks7-mime)
177 | - For Python 2.6, argparse is now a requirement
178 | - Added constants for TAXII Default Query Parameters and Relationships
179 |
180 | Bug fixes:
181 |
182 | - In messages_11.PollResponse, the result_part_number parameter is now set by the constructor.
183 |
184 |
185 | 1.1.102
186 | -------
187 | `(diff) `__
188 |
189 | The biggest change was the addition of scripts to libtaxii. Now when you install libtaxii, you get
190 | a number of scripts that are by default configured to hit the TAXII Test server (taxiitest.mitre.org).
191 | You can specify a number of parameters on the command line to change where/how the scripts connect.
192 | The scripts are:
193 |
194 | - discovery_client - Calls a TAXII 1.1 Discovery Service
195 | - fulfillment_client - Calls a TAXII 1.1 Poll Service for Poll Fulfillment
196 | - inbox_client - Calls a TAXII 1.1 Inbox Service. Comes packaged with a STIX document to use by default.
197 | - poll_client - Calls a TAXII 1.1 Poll Service
198 | - poll_client_10 - Calls a TAXII 1.0 Poll Service (Note: Does not work with taxiitest.mitre.org, as taxiitest.mitre.org is TAXII 1.1 only)
199 | - query_client - Calls a TAXII 1.1 Poll Service with a query on IP or File Hash (Note: As of 6/11/2014; Works with the master branch of YETI, and will work with YETI after the next release of YETI)
200 |
201 | We also had a number of bug fixes and impprovements for this version of libtaxii:
202 |
203 | - Unicode strings work round trip (Hat tip to Ben Yates for reporting the issue)
204 | - Added TONS of documentation (http://libtaxii.readthedocs.org/en/latest/index.html). Big thanks to @gtback and @slsnow!
205 | - Fixed some issues in ContentBlock.content where certain data was not serializing/deserializing properly
206 | - Streamlined serialization of XML documents to avoid a double-parse in certain cases
207 | - Added a Content Binding ID for STIX XML 1.1.1
208 | - Added an optional pretty_print argument to all to_xml() functions. e.g., to_xml(pretty_print=True)
209 | - Added the three TAXII Default Query Status Type to libtaxii.taxii_default_query
210 | - Fixed a bug where custom Status Types were prohibited
211 | - Added Travis CI
212 |
213 |
214 | 1.1.101
215 | -------
216 |
217 | `(diff) `__
218 |
219 | Lots of changes in this release, including some important bug fixes.
220 |
221 | - The equals method for all TAXII Messages was fixed (previous it would
222 | incorrectly return True in many cases).
223 | - Fixed various serialization/deserialization issues uncovered by the now
224 | correctly implemented equals methods.
225 | - Added a defined Content-Type for TAXII XML 1.1.
226 | - Corrected the value of ST\_UNSUPPORTED\_PROTOCOL.
227 | - Fixed a bug when parsing non-TAXII responses.
228 | - Fixed a bug where the Subscription ID was not allowed to be none in
229 | ManageFeedSubscriptionRequest (The Subscription ID must be None for
230 | subscription requests with an action of SUBSCRIBE).
231 | - Fixed a bug where DeliveryParameters were not permitted to be None in a
232 | ManageFeedSubscriptionRequest.
233 | - Added code to permit the setting of certain HTTP Headers (Accept,
234 | X-TAXII-Accept).
235 | - Improved libtaxii's handling of non-XML content that looks like XML
236 | - Added Constants for TAXII Headers (and updated the code to use them).
237 | - Improved handling of non-registered Query formats (now an exception is
238 | raised; previously None was returned).
239 | - libtaxii now provides an X-TAXII-Services header.
240 |
241 |
242 | 1.1.100
243 | -------
244 |
245 | `(diff) `__
246 |
247 | *This version contains known bugs. Use a more recent version of libtaxii
248 | when possible.*
249 |
250 | - First release that supports TAXII 1.1.
251 | - No changes to TAXII 1.0 code.
252 | - Added documentation for Messages 1.1 API and TAXII Default Query.
253 |
254 |
255 | 1.0.107
256 | -------
257 |
258 | `(diff) `__
259 |
260 | - Fixed an issue that was causing invalid TAXII XML to be generated
261 | (Thanks [@JamesNK](https://github.com/JamesNK)).
262 | - Fixed an issue in the messages test suite that caused the invalid XML
263 | to not be caught.
264 |
265 |
266 | 1.0.106
267 | -------
268 |
269 | `(diff) `__
270 |
271 | - Added validation to messages.py. This should not cause any backwards
272 | compatibility issues, but there may be things we didn't catch. Please
273 | report any instances of this via the issue tracker.
274 | - Modified the internals of ``from_dict()`` and ``from_xml()`` in many
275 | cases to support how validation now works.
276 | - Added constructor arguments to HttpClient. Default behavior is still
277 | the same.
278 | - Added the ability to specify whether or not an HTTP Server's SSL
279 | Certificate should be verified.
280 | - Prettified some of the documentation.
281 | - Added documentation in certain places where there was none previously.
282 |
283 |
284 | 1.0.105
285 | -------
286 |
287 | `(diff) `__
288 |
289 | - Added support for JSON (Thanks to [@ics](https://github.com/ics),
290 | Alex Ciobanu of CERT EU).
291 | - callTaxiiService2 now supports user-specified content\_types (Thanks
292 | to Alex Ciobanu of CERT EU).
293 | - Fixed `Issue #18 `__,
294 | libtaxii.messages now permits users to specify any lxml parser for
295 | parsing XML. A default parser is used when one is not specified,
296 | which is unchanged from previous usage.
297 |
298 |
299 | 1.0.104
300 | -------
301 |
302 | `(diff) `__
303 |
304 | - Many of the comments were aligned with PEP8 guidelines (thanks
305 | [@gtback](https://github.com/gtback)!)
306 | - Added a new authentication mechanism (AUTH\_CERT\_BASIC) to
307 | clients.py. This authentication mechanism supports Certificate
308 | Authentication plus HTTP Basic authentication.
309 | - Added clients.HttpClient.callTaxiiService2, which supersedes
310 | callTaxiiService. The previous version of callTaxiiService couldn't
311 | handle proxies well, which now have better support.
312 | - Added better proxy support to client.HttpClient via the setProxy()
313 | function.
314 |
315 |
316 | 1.0.103
317 | -------
318 |
319 | `(diff) `__
320 |
321 | This version fixes a schema validation bug. Schema validation did not work
322 | prior to this version.
323 |
324 |
325 | 1.0.102
326 | -------
327 |
328 | `(diff) `__
329 |
330 | This version adds better proxy support to libtaxii in libtaxii.clients. A
331 | function to set a proxy (setProxy) was added as well as a new callTaxiiService2
332 | function that can properly use proxies. The original callTaxiiService function
333 | did not support proxies well. The APIs have the full documentation for
334 | callTaxiiService, callTaxiiService2, and setProxy (`Client API
335 | `__).
336 |
337 |
338 | 1.0.101
339 | -------
340 |
341 | `(diff) `__
342 |
343 | This version added missing source files for distribution on PyPI. No
344 | functionality changes were made.
345 |
346 |
347 | 1.0.100
348 | -------
349 |
350 | `(diff) `__
351 |
352 | Version 1.0.100 represents the first TAXII 1.0 compliant version of libtaxii.
353 | This version removes all code not compliant with TAXII 1.0.
354 |
355 |
356 | 1.0.090
357 | -------
358 |
359 | `(diff) `__
360 |
361 | This version of libtaxii has components that are TAXII 1.0 conformant and
362 | experimental functionality that conforms to a draft version of TAXII. This
363 | version should only be used to transition from 1.0.000draft to 1.0.100.
364 |
365 |
366 | 1.0.000draft
367 | ------------
368 |
369 | This version of libtaxii represents experimental functionality that conforms to
370 | a draft version of TAXII. This code should no longer be used. For those using
371 | this code, you should upgrade to 1.0.090 and migrate your code to use the TAXII
372 | 1.0 components, then transition to 1.0.100.
373 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2017, The MITRE Corporation
2 | # For license information, see the LICENSE.txt file
3 |
4 | import os
5 |
6 | import libtaxii
7 |
8 | project = u'libtaxii'
9 | copyright = u'2017, The MITRE Corporation'
10 | version = libtaxii.__version__
11 | release = version
12 |
13 | extensions = [
14 | 'sphinx.ext.autodoc',
15 | 'sphinx.ext.doctest',
16 | 'sphinx.ext.ifconfig',
17 | 'sphinx.ext.intersphinx',
18 | 'sphinx.ext.viewcode',
19 | 'sphinx.ext.napoleon',
20 | ]
21 |
22 | intersphinx_mapping = {
23 | 'python': ('https://docs.python.org/', None),
24 | }
25 |
26 | templates_path = ['_templates']
27 | source_suffix = '.rst'
28 | master_doc = 'index'
29 |
30 | rst_prolog = """
31 | **Version**: {0}
32 | """.format(release)
33 |
34 | exclude_patterns = [
35 | '_build',
36 | ]
37 |
38 | on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
39 | if not on_rtd:
40 | import sphinx_rtd_theme
41 | html_theme = 'sphinx_rtd_theme'
42 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
43 | else:
44 | html_theme = 'default'
45 |
46 | latex_elements = {}
47 | latex_documents = [
48 | ('index', 'libtaxii.tex', u'libtaxii Documentation',
49 | u'The MITRE Corporation', 'manual'),
50 | ]
51 |
--------------------------------------------------------------------------------
/docs/getting_started.rst:
--------------------------------------------------------------------------------
1 | Getting Started
2 | ===============
3 |
4 | This page gives an introduction to **libtaxii** and how to use it. Please note
5 | that this page is being actively worked on and feedback is welcome.
6 |
7 |
8 | Modules
9 | -------
10 |
11 | The libtaxii library contains the following modules:
12 |
13 | * **libtaxii** - Contains version info and some methods for getting TAXII Messages
14 | from HTTP responses. (Implemented in ``libtaxii/__init__.py``)
15 | * **libtaxii.clients.** - TAXII HTTP and HTTPS clients. (Implemented in
16 | ``libtaxii/clients.py``)
17 | * **libtaxii.common** - Contains functions and classes useful for all versions of TAXII
18 | * **libtaxii.constants** - Contains constants for TAXII
19 | * **libtaxii.messages_10** - Creating, handling, and parsing TAXII 1.0
20 | messages. (Implemented in ``libtaxii/messages_10.py``)
21 | * **libtaxii.messages_11** - Creating, handling, and parsing TAXII 1.1
22 | messages. (Implemented in ``libtaxii/messages_11.py``)
23 | * **libtaxii.taxii_default_query** - Creating, handling and parsing TAXII
24 | Default Queries. (Implemented in ``libtaxii/taxii_default_query.py``) *New in
25 | libtaxii 1.1.100*.
26 | * **libtaxii.validation** - Common data validation functions used across
27 | libtaxii. (Implemented in ``libtaxii/validation.py``)
28 |
29 | TAXII Messages Module Structure
30 | -------------------------------
31 |
32 | In the TAXII message modules (:py:mod:`libtaxii.messages_10` and
33 | :py:mod:`libtaxii.messages_11`), there is a class corresponding to each type of
34 | TAXII message. For example, there is a ``DiscoveryRequest`` class for the
35 | Discovery Request message:
36 |
37 | .. code:: python
38 |
39 | import libtaxii.messages_11 as tm11
40 | discovery_request = tm11.DiscoveryRequest( ... )
41 |
42 | For types that can been used across multiple messages (e.g., a Content Block
43 | can exist in both Poll Response and Inbox Message), the corresponding class
44 | (``ContentBlock``) is (and always has always been) defined at the module level.
45 |
46 | .. code:: python
47 |
48 | content_block = tm11.ContentBlock( ... )
49 |
50 | Other types that are used exclusively within a particular TAXII message type
51 | were previously defined as nested classes on the corresponding message class;
52 | however, they are now defined at the top level of the module. For example, a
53 | Service Instance is only used in a Discovery Response message, so the class
54 | representing a Service Instance, now just ``ServiceInstance``, was previously
55 | ``DiscoveryResponse.ServiceInstance``. The latter name still works for backward
56 | compatibilty reasons, but is deprecated and may be removed in the future.
57 |
58 | .. code:: python
59 |
60 | service_instance = tm11.ServiceInstance( ... )
61 | service_instance = tm11.DiscoveryRequest.ServiceInstance( ... )
62 |
63 | See the :ref:`API Documentation ` for proper constructor arguments for
64 | each type above.
65 |
66 |
67 | TAXII Message Serialization and Deserialization
68 | -----------------------------------------------
69 |
70 | Each class in the message modules has serialization and deserialization methods
71 | for XML Strings, Python dictionaries, and LXML ElementTrees. All serialization
72 | methods (``to_*()``) are instance methods called on specific objects (e.g.,
73 | ``discovery_request.to_xml()``). Deserialization methods (``from_*()``) are
74 | class methods and should be called on the class itself (e.g.,
75 | ``tm11.DiscoveryRequest.from_xml(xml_string)``).
76 |
77 | Each class in messages.py defines the following:
78 |
79 | * ``from_xml(xml_string)`` - Creates an instance of the class from an XML String.
80 | * ``to_xml()`` - Creates the XML representation of an instance of a class.
81 | * ``from_dict(dictionary)`` - Creates an instance of the class from a Python dictionary.
82 | * ``to_dict()`` - Creates the Python dictionary representation of an instance of a class.
83 | * ``from_etree(lxml_etree)`` - Creates an instance of the class from an LXML Etree.
84 | * ``to_etree()`` - Creates the LXML Etree representation of an instance of a class.
85 |
86 | To create a TAXII Message from XML:
87 |
88 | .. code:: python
89 |
90 | xml_string = '' # Note: Invalid XML
91 | discovery_response = tm11.DiscoveryResponse.from_xml(xml_string)
92 |
93 | To create an XML string from a TAXII Message:
94 |
95 | .. code:: python
96 |
97 | new_xml_string = discovery_response.to_xml()
98 |
99 | The same approach can be used for Python dictionaries:
100 |
101 | .. code:: python
102 |
103 | msg_dict = { ... } # Note: Invalid dictionary syntax
104 | discovery_response = tm11.DiscoveryResponse.from_dict(msg_dict)
105 | new_dict = discovery_response.to_dict()
106 |
107 | and for LXML ElementTrees:
108 |
109 | .. code:: python
110 |
111 | msg_etree = etree.Element( ... ) # Note: Invalid Element constructor
112 | discovery_response = tm11.DiscoveryResponse.from_etree(msg_etree)
113 | new_etree = discovery_response.to_etree()
114 |
115 | Schema Validating TAXII Messages
116 | --------------------------------
117 | You can use libtaxii to Schema Validate XML, etree, and file representations of TAXII Messages.
118 | XML Schema validation cannot be performed on a TAXII Message Python object, since XML Schema validation
119 | can only be performed on XML.
120 |
121 | A full code example of XML Schema validation can be found in :ref:`API Documentation `
122 |
123 |
124 | TAXII Clients
125 | -------------
126 |
127 | The **libtaxii.clients** module defines a single class ``HttpClient`` capable
128 | of invoking TAXII services over both HTTP and HTTPS. The client is a fairly
129 | straighforward wrapper around Python's builtin ``httplib`` and supports the use
130 | of of both HTTP Basic and TLS Certificate authentication.
131 |
132 | Example usage of clients:
133 |
134 | .. code:: python
135 |
136 | import libtaxii as t
137 | import libtaxii.clients as tc
138 | import libtaxii.messages_11 as tm11
139 | from libtaxii.constants import *
140 |
141 | client = tc.HttpClient()
142 | client.set_auth_type(tc.HttpClient.AUTH_BASIC)
143 | client.set_use_https(True)
144 | client.set_auth_credentials({'username': 'MyUsername', 'password': 'MyPassword'})
145 |
146 | discovery_request = tm11.DiscoveryRequest(tm11.generate_message_id())
147 | discovery_xml = discovery_request.to_xml()
148 |
149 | http_resp = client.call_taxii_service2('example.com', '/pollservice/', VID_TAXII_XML_11, discovery_xml)
150 | taxii_message = t.get_message_from_http_response(http_resp, discovery_request.message_id)
151 | print taxii_message.to_xml()
152 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | libtaxii |release| Documentation
2 | ================================
3 |
4 | **libtaxii** is a Python library that provides:
5 |
6 | 1. An object representation of TAXII Messages
7 | 2. Serialization/deserialization to and from XML and Python dictionaries
8 | 3. An HTTP/HTTPS TAXII Client
9 |
10 | .. toctree::
11 | :maxdepth: 2
12 |
13 | installation
14 | getting_started
15 | scripts
16 | changes
17 |
18 | API Reference
19 | =============
20 |
21 | .. toctree::
22 | :maxdepth: 2
23 |
24 | api/modules
25 |
26 | Indices and tables
27 | ==================
28 |
29 | * :ref:`genindex`
30 | * :ref:`modindex`
31 | * :ref:`search`
32 |
33 | Offline Documentation
34 | =====================
35 | To download the latest documentation for offline use, please use one of these links:
36 |
37 | * `PDF `_
38 | * `HTML `_
39 |
--------------------------------------------------------------------------------
/docs/installation.rst:
--------------------------------------------------------------------------------
1 | .. _installation:
2 |
3 | Installation
4 | ============
5 |
6 | Recommended Installation
7 | ------------------------
8 |
9 | Use pip_:
10 |
11 | .. code-block:: bash
12 |
13 | $ pip install libtaxii
14 |
15 | You might also want to consider using a virtualenv_.
16 |
17 | .. _pip: http://pip.readthedocs.org/
18 | .. _virtualenv: http://virtualenv.readthedocs.org/
19 |
20 |
21 | Dependencies
22 | ------------
23 |
24 | The libtaxii library is developed on Python 2.7 and tested against both
25 | Python 2.6 and 2.7. Besides the Python Standard Library, libtaxii relies on
26 | the following Python libraries:
27 |
28 | * lxml_ - A Pythonic binding for the C libraries **libxml2** and
29 | **libxslt**.
30 | * python-dateutil_ - A library for parsing datetime information.
31 |
32 | Each of these can be installed with ``pip`` or by manually downloading packages
33 | from PyPI. On Windows, you will probably have the most luck using `pre-compiled
34 | binaries`_ for ``lxml``. On Ubuntu (12.04 or 14.04), you should make sure the
35 | following packages are installed before attempting to compile ``lxml`` from
36 | source:
37 |
38 | * libxml2-dev
39 | * libxslt1-dev
40 | * zlib1g-dev
41 |
42 | .. note::
43 |
44 | In libtaxii 1.0.101 and earlier, the M2Crypto library was also required.
45 | This dependency was removed as of libtaxii 1.0.102.
46 |
47 | .. warning::
48 |
49 | Users have encountered errors with versions of libxml2 (a dependency of
50 | lxml) prior to version 2.9.1. The default version of libxml2 provided on
51 | Ubuntu 12.04 is currently 2.7.8. Users are encouraged to upgrade libxml2
52 | manually if they have any issues. Ubuntu 14.04 provides libxml2 version
53 | 2.9.1.
54 |
55 | .. _lxml: http://lxml.de/
56 | .. _python-dateutil: http://labix.org/python-dateutil
57 | .. _pre-compiled binaries: http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml
58 | .. _M2Crypto: http://chandlerproject.org/Projects/MeTooCrypto
59 |
60 |
61 | Manual Installation
62 | -------------------
63 |
64 | If you are unable to use pip, you can also install libtaxii with setuptools_.
65 | If you don't already have setuptools installed, please install it before
66 | continuing.
67 |
68 | 1. Download and install the dependencies_ above. Although setuptools will
69 | generally install dependencies automatically, installing the dependencies
70 | manually beforehand helps distinguish errors in dependency installation from
71 | errors in libtaxii installation. Make sure you check to ensure the
72 | versions you install are compatible with the version of libtaxii you plan
73 | to install.
74 |
75 | 2. Download the desired version of libtaxii from PyPI_ or the GitHub releases_
76 | page. The steps below assume you are using the |release| release.
77 |
78 | 3. Extract the downloaded file. This will leave you with a directory named
79 | libtaxii-|release|.
80 |
81 | .. parsed-literal::
82 | $ tar -zxf libtaxii-|release|.tar.gz
83 | $ ls
84 | libtaxii-|release| libtaxii-|release|.tar.gz
85 |
86 | OR
87 |
88 | .. parsed-literal::
89 | $ unzip libtaxii-|release|.zip
90 | $ ls
91 | libtaxii-|release| libtaxii-|release|.zip
92 |
93 | 4. Run the installation script.
94 |
95 | .. parsed-literal::
96 | $ cd libtaxii-|release|
97 | $ python setup.py install
98 |
99 | 5. Test the installation.
100 |
101 | .. parsed-literal::
102 | $ python
103 | Python 2.7.6 (default, Mar 22 2014, 22:59:56)
104 | [GCC 4.8.2] on linux2
105 | Type "help", "copyright", "credits" or "license" for more information.
106 | >>> import libtaxii
107 | >>>
108 |
109 | If you don't see an ``ImportError``, the installation was successful.
110 |
111 | .. _setuptools: https://pypi.python.org/pypi/setuptools/
112 | .. _PyPI: https://pypi.python.org/pypi/libtaxii/
113 | .. _releases: https://github.com/TAXIIProject/libtaxii/releases
114 |
115 |
116 | Further Information
117 | -------------------
118 |
119 | If you're new to installing Python packages, you can learn more at the `Python
120 | Packaging User Guide`_, specifically the `Installing Python Packages`_ section.
121 |
122 | .. _Python Packaging User Guide: http://python-packaging-user-guide.readthedocs.org/
123 | .. _Installing Python Packages: http://python-packaging-user-guide.readthedocs.org/en/latest/tutorial.html#installing-python-packages
124 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | REM Command file for Sphinx documentation
4 |
5 | if "%SPHINXBUILD%" == "" (
6 | set SPHINXBUILD=sphinx-build
7 | )
8 | set BUILDDIR=_build
9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
10 | set I18NSPHINXOPTS=%SPHINXOPTS% .
11 | if NOT "%PAPER%" == "" (
12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
14 | )
15 |
16 | if "%1" == "" goto help
17 |
18 | if "%1" == "help" (
19 | :help
20 | echo.Please use `make ^` where ^ is one of
21 | echo. html to make standalone HTML files
22 | echo. dirhtml to make HTML files named index.html in directories
23 | echo. singlehtml to make a single large HTML file
24 | echo. pickle to make pickle files
25 | echo. json to make JSON files
26 | echo. htmlhelp to make HTML files and a HTML help project
27 | echo. qthelp to make HTML files and a qthelp project
28 | echo. devhelp to make HTML files and a Devhelp project
29 | echo. epub to make an epub
30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
31 | echo. text to make text files
32 | echo. man to make manual pages
33 | echo. texinfo to make Texinfo files
34 | echo. gettext to make PO message catalogs
35 | echo. changes to make an overview over all changed/added/deprecated items
36 | echo. xml to make Docutils-native XML files
37 | echo. pseudoxml to make pseudoxml-XML files for display purposes
38 | echo. linkcheck to check all external links for integrity
39 | echo. doctest to run all doctests embedded in the documentation if enabled
40 | goto end
41 | )
42 |
43 | if "%1" == "clean" (
44 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
45 | del /q /s %BUILDDIR%\*
46 | goto end
47 | )
48 |
49 |
50 | %SPHINXBUILD% 2> nul
51 | if errorlevel 9009 (
52 | echo.
53 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
54 | echo.installed, then set the SPHINXBUILD environment variable to point
55 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
56 | echo.may add the Sphinx directory to PATH.
57 | echo.
58 | echo.If you don't have Sphinx installed, grab it from
59 | echo.http://sphinx-doc.org/
60 | exit /b 1
61 | )
62 |
63 | if "%1" == "html" (
64 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
65 | if errorlevel 1 exit /b 1
66 | echo.
67 | echo.Build finished. The HTML pages are in %BUILDDIR%/html.
68 | goto end
69 | )
70 |
71 | if "%1" == "dirhtml" (
72 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
73 | if errorlevel 1 exit /b 1
74 | echo.
75 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
76 | goto end
77 | )
78 |
79 | if "%1" == "singlehtml" (
80 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
81 | if errorlevel 1 exit /b 1
82 | echo.
83 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
84 | goto end
85 | )
86 |
87 | if "%1" == "pickle" (
88 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
89 | if errorlevel 1 exit /b 1
90 | echo.
91 | echo.Build finished; now you can process the pickle files.
92 | goto end
93 | )
94 |
95 | if "%1" == "json" (
96 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
97 | if errorlevel 1 exit /b 1
98 | echo.
99 | echo.Build finished; now you can process the JSON files.
100 | goto end
101 | )
102 |
103 | if "%1" == "htmlhelp" (
104 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
105 | if errorlevel 1 exit /b 1
106 | echo.
107 | echo.Build finished; now you can run HTML Help Workshop with the ^
108 | .hhp project file in %BUILDDIR%/htmlhelp.
109 | goto end
110 | )
111 |
112 | if "%1" == "qthelp" (
113 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
114 | if errorlevel 1 exit /b 1
115 | echo.
116 | echo.Build finished; now you can run "qcollectiongenerator" with the ^
117 | .qhcp project file in %BUILDDIR%/qthelp, like this:
118 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\libtaxii.qhcp
119 | echo.To view the help file:
120 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\libtaxii.ghc
121 | goto end
122 | )
123 |
124 | if "%1" == "devhelp" (
125 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
126 | if errorlevel 1 exit /b 1
127 | echo.
128 | echo.Build finished.
129 | goto end
130 | )
131 |
132 | if "%1" == "epub" (
133 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
134 | if errorlevel 1 exit /b 1
135 | echo.
136 | echo.Build finished. The epub file is in %BUILDDIR%/epub.
137 | goto end
138 | )
139 |
140 | if "%1" == "latex" (
141 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
142 | if errorlevel 1 exit /b 1
143 | echo.
144 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
145 | goto end
146 | )
147 |
148 | if "%1" == "latexpdf" (
149 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
150 | cd %BUILDDIR%/latex
151 | make all-pdf
152 | cd %BUILDDIR%/..
153 | echo.
154 | echo.Build finished; the PDF files are in %BUILDDIR%/latex.
155 | goto end
156 | )
157 |
158 | if "%1" == "latexpdfja" (
159 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
160 | cd %BUILDDIR%/latex
161 | make all-pdf-ja
162 | cd %BUILDDIR%/..
163 | echo.
164 | echo.Build finished; the PDF files are in %BUILDDIR%/latex.
165 | goto end
166 | )
167 |
168 | if "%1" == "text" (
169 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
170 | if errorlevel 1 exit /b 1
171 | echo.
172 | echo.Build finished. The text files are in %BUILDDIR%/text.
173 | goto end
174 | )
175 |
176 | if "%1" == "man" (
177 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
178 | if errorlevel 1 exit /b 1
179 | echo.
180 | echo.Build finished. The manual pages are in %BUILDDIR%/man.
181 | goto end
182 | )
183 |
184 | if "%1" == "texinfo" (
185 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
186 | if errorlevel 1 exit /b 1
187 | echo.
188 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
189 | goto end
190 | )
191 |
192 | if "%1" == "gettext" (
193 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
194 | if errorlevel 1 exit /b 1
195 | echo.
196 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
197 | goto end
198 | )
199 |
200 | if "%1" == "changes" (
201 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
202 | if errorlevel 1 exit /b 1
203 | echo.
204 | echo.The overview file is in %BUILDDIR%/changes.
205 | goto end
206 | )
207 |
208 | if "%1" == "linkcheck" (
209 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
210 | if errorlevel 1 exit /b 1
211 | echo.
212 | echo.Link check complete; look for any errors in the above output ^
213 | or in %BUILDDIR%/linkcheck/output.txt.
214 | goto end
215 | )
216 |
217 | if "%1" == "doctest" (
218 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
219 | if errorlevel 1 exit /b 1
220 | echo.
221 | echo.Testing of doctests in the sources finished, look at the ^
222 | results in %BUILDDIR%/doctest/output.txt.
223 | goto end
224 | )
225 |
226 | if "%1" == "xml" (
227 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
228 | if errorlevel 1 exit /b 1
229 | echo.
230 | echo.Build finished. The XML files are in %BUILDDIR%/xml.
231 | goto end
232 | )
233 |
234 | if "%1" == "pseudoxml" (
235 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
236 | if errorlevel 1 exit /b 1
237 | echo.
238 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
239 | goto end
240 | )
241 |
242 | :end
243 |
--------------------------------------------------------------------------------
/docs/scripts.rst:
--------------------------------------------------------------------------------
1 | Scripts
2 | =======
3 |
4 | This page provides documentation on the scripts that are included with libtaxii. All
5 | clients are configured to use the Hail A TAXII server (http://hailataxii.com/) by
6 | default; provide command line options for specifying most aspects of the script (e.g.,
7 | host, port, client certs, username/password, HTTP or HTTPS, etc); and support TAXII 1.1
8 | unless otherwise noted.
9 |
10 | Note that the scripts *should* be callable from anywhere on the command line as long as you have
11 | the python scripts directory on your path.
12 |
13 | Script Listing
14 | --------------
15 |
16 | * **discovery_client** - Issues a Discovery Request to a Discovery Service
17 | * **fulfillment_client** - Issues a Poll Fulfillment Request to a Poll Service and writes the resulting content to file
18 | * **inbox_client** - Issues an Inbox Message with one Content Block to an Inbox Service
19 | * **poll_client** - Issues a Poll Request to a Poll Service and writes the resulting content to file
20 | * **poll_client_10** - Issues a Poll Request to a TAXII 1.0 Poll Service and writes the resulting content to file
21 | * **query_client** - Issues a Query for an IP Address or Hash to a Poll Service and writes the resulting content to file
22 |
23 | Common Command Line Arguments
24 | -----------------------------
25 | All scripts use these command line arguments:
26 |
27 | * ``-h, --help`` - Shows help text
28 | * ``-u, --url`` - Specified the URL to connect to.
29 | * ``--cert`` - Specifies the file location of the certificate to use for
30 | authentication. If provided, ``--key`` must also be provided.
31 | * ``--key`` - Specifies the file location of the key to use for authentication.
32 | * ``--username`` - Specifies the username to use for authentication. If
33 | provided, ``--pass`` must also be provided.
34 | * ``--pass`` - Specifies the password to use for authentication.
35 | * ``--proxy`` - Specifies proxy settings (e.g. ``http://proxy.example.com:80/``,
36 | or ``noproxy`` to not use any proxy). If omitted, the system's proxy settings
37 | will be used.
38 | * ``--xml-output`` - Specifies that the XML messages should be printed instead of the default textual representation
39 |
40 | Note: As of libtaxii 1.1.106, the following arguments are now deprecated in favor of ``--url``
41 |
42 | * ``--host`` - Specifies the host to connect to (e.g., ``hailataxii.com``)
43 | * ``--port`` - Specifies the port to connect on (e.g., ``80``)
44 | * ``--path`` - Specifies the path portion of the URL to connect to
45 | (e.g., ``/services/discovery``)
46 | * ``--https`` - Specifies whether to use HTTPS or not (e.g., True or False)
47 |
48 | For example, to call the discovery_client using all these arguments, you would do:
49 | ``discovery_client --url http://hailataxii.com/taxii-discovery-service --cert MyCert.crt --key MyKey.key --username foo --pass bar --proxy http://myproxy.example.com:80 --xml-output``
50 |
51 | Additional Discovery Client Command Line Arguments
52 | --------------------------------------------------
53 | The Discovery Client does not use any additional command line arguments.
54 |
55 | Additional Poll Fulfillment Client Command Line Arguments
56 | ---------------------------------------------------------
57 | In addition to the command line arguments listed above, the Poll Fulfillment Client uses these:
58 |
59 | * ``--collection`` - The collection being requested
60 | * ``--result_id`` - The result id being requested (required)
61 | * ``--result_part_number`` - The result part number being requested (defaults to 1)
62 |
63 | Example: ``fulfillment_client --collection MyCollection --result_id someId --result_part_number 1``
64 |
65 | Additional Inbox Client Command Line Arguments
66 | ----------------------------------------------
67 | In addition to the command line arguments listed above, the Inbox Client uses these:
68 |
69 | * ``--content-binding`` - The Content Binding ID to use for the Content Block (Defaults to STIX XML 1.1)
70 | * ``--subtype`` - The Content Binding ID subtype to use for the Content Block (Optional; Defaults to None)
71 | * ``--content-file`` - The file location (e.g., /tmp/mydata) containing the data to send in the Content Block. Defaults to a built-in STIX 1.1 XML document.
72 | * ``--dcn`` - The Destination Collection Name that is specified in the Inbox Message, requesting that the recipient
73 | make the sent content available on the specified Destination Collection Name. TAXII supports multiple DCNs, but
74 | this script only supports one.
75 |
76 | Example: ``inbox_client --content-binding urn:stix.mitre.org:xml:1.1 --content-file stix_file.xml``
77 |
78 | Additional Poll Client Command Line Arguments
79 | ---------------------------------------------
80 | In addition to the command line arguments listed above, the Poll Client uses these:
81 |
82 | * ``--collection`` - The Collection Name to Poll. Defaults to 'default'
83 | * ``--begin_timestamp`` - The Begin Timestamp Label to used bound the Poll Request. Defaults to None.
84 | * ``--end_timestamp`` - The End Timestamp Label to used bound the Poll Request. Defaults to None.
85 | * ``--subscription-id`` - The Subscription ID for this Poll Request
86 | * ``--dest-dir`` - The directory to save Content Blocks to. Defaults to the current directory.
87 |
88 | Example: ``poll_client --collection MyCollection``
89 |
90 | Additional Poll Client 1.0 Command Line Arguments
91 | -------------------------------------------------
92 | In addition to the command line arguments listed above, the Poll Client 1.0 uses these:
93 |
94 | * ``--feed`` - The Data Feed to Poll. Defaults to 'default'
95 | * ``--begin_timestamp`` - The Begin Timestamp Label to used bound the Poll Request. Defaults to None.
96 | * ``--end_timestamp`` - The End Timestamp Label to used bound the Poll Request. Defaults to None.
97 | * ``--subscription-id`` - The Subscription ID to use when polling
98 | * ``--dest-dir`` - The directory to save Content Blocks to. Defaults to the current directory.
99 |
100 | Example: ``poll_client_10 --feed MyFeedName --subscription-id SomeSubscriptionId``
101 |
102 | Additional Query Client Command Line Arguments
103 | ----------------------------------------------
104 | In addition to the command line arguments listed above, the Query Client uses these:
105 |
106 | * ``--collection`` - The collection to Poll (recall that a query is part of a Poll Request). Defaults to 'default_queryable'.
107 | * ``--allow_asynch`` - Whether asynchronous Polling is supported. Defaults to True (Use the Poll Fulfillment client to request asynchronous results!)
108 | * ``--ip`` - The IP to query on. One of --ip or --hash must be specified.
109 | * ``--hash`` - The file hash to query on. One of --ip or --hash must be specified.
110 | * ``--dest-dir`` - The directory to save Content Blocks to. Defaults to the current directory.
111 |
112 | Example: ``query_client --collection MyQueryCollection --ip 10.0.0.0``
113 |
--------------------------------------------------------------------------------
/libtaxii/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2017, The MITRE Corporation
2 | # For license information, see the LICENSE.txt file
3 |
4 | """
5 | The main libtaxii module
6 | """
7 |
8 | import six
9 | from six.moves import urllib
10 |
11 | import libtaxii.messages_10 as tm10
12 | import libtaxii.messages_11 as tm11
13 | import libtaxii.clients as tc
14 | from .constants import *
15 |
16 | import cgi
17 |
18 | from .version import __version__ # noqa
19 |
20 |
21 | def get_message_from_http_response(http_response, in_response_to):
22 | """Create a TAXII message from an HTTPResponse object.
23 |
24 | This function parses the :py:class:`httplib.HTTPResponse` by reading the
25 | X-TAXII-Content-Type HTTP header to determine if the message binding is
26 | supported. If the X-TAXII-Content-Type header is present and the value
27 | indicates a supported Message Binding, this function will attempt to parse
28 | the HTTP Response body.
29 |
30 | If the X-TAXII-Content-Type header is not present, this function will
31 | attempt to build a Failure Status Message per the HTTP Binding 1.0
32 | specification.
33 |
34 | If the X-TAXII-Content-Type header is present and indicates an unsupported
35 | Message Binding, this function will raise a ValueError.
36 |
37 | Args:
38 | http_response (httplib.HTTPResponse): the HTTP response to
39 | parse
40 | in_response_to (str): the default value for in_response_to
41 | """
42 | if isinstance(http_response, six.moves.http_client.HTTPResponse):
43 | return get_message_from_httplib_http_response(http_response, in_response_to)
44 | elif isinstance(http_response, urllib.error.HTTPError):
45 | return get_message_from_urllib2_httperror(http_response, in_response_to)
46 | elif isinstance(http_response, urllib.response.addinfourl):
47 | return get_message_from_urllib_addinfourl(http_response, in_response_to)
48 | else:
49 | raise ValueError('Unsupported response type: %s.' % http_response.__class__.__name__)
50 |
51 |
52 | def get_message_from_urllib2_httperror(http_response, in_response_to):
53 | """ This function should not be called by libtaxii users directly. """
54 | info = http_response.info()
55 |
56 | if hasattr(info, 'getheader'):
57 | taxii_content_type = info.getheader('X-TAXII-Content-Type')
58 | _, params = cgi.parse_header(info.getheader('Content-Type'))
59 | else:
60 | taxii_content_type = info.get('X-TAXII-Content-Type')
61 | _, params = cgi.parse_header(info.get('Content-Type'))
62 |
63 | encoding = params.get('charset', 'utf-8')
64 | response_message = six.ensure_text(http_response.read(), errors='replace')
65 |
66 | if taxii_content_type is None:
67 | m = str(http_response) + '\r\n' + str(http_response.info()) + '\r\n' + response_message
68 | return tm11.StatusMessage(message_id='0', in_response_to=in_response_to, status_type=ST_FAILURE, message=m)
69 | elif taxii_content_type == VID_TAXII_XML_10: # It's a TAXII XML 1.0 message
70 | return tm10.get_message_from_xml(response_message, encoding)
71 | elif taxii_content_type == VID_TAXII_XML_11: # It's a TAXII XML 1.1 message
72 | return tm11.get_message_from_xml(response_message, encoding)
73 | elif taxii_content_type == VID_CERT_EU_JSON_10:
74 | return tm10.get_message_from_json(response_message, encoding)
75 | else:
76 | raise ValueError('Unsupported X-TAXII-Content-Type: %s' % taxii_content_type)
77 |
78 |
79 | def get_message_from_urllib_addinfourl(http_response, in_response_to):
80 | """ This function should not be called by libtaxii users directly. """
81 | info = http_response.info()
82 |
83 | if hasattr(info, 'getheader'):
84 | taxii_content_type = info.getheader('X-TAXII-Content-Type')
85 | _, params = cgi.parse_header(info.getheader('Content-Type'))
86 | else:
87 | taxii_content_type = info.get('X-TAXII-Content-Type')
88 | _, params = cgi.parse_header(info.get('Content-Type'))
89 |
90 | encoding = params.get('charset', 'utf-8')
91 | response_message = six.ensure_text(http_response.read(), errors='replace')
92 |
93 | if taxii_content_type is None: # Treat it as a Failure Status Message, per the spec
94 |
95 | message = []
96 | header_dict = six.iteritems(http_response.info().dict)
97 | for k, v in header_dict:
98 | message.append(k + ': ' + v + '\r\n')
99 | message.append('\r\n')
100 | message.append(response_message)
101 |
102 | m = ''.join(message)
103 |
104 | return tm11.StatusMessage(message_id='0', in_response_to=in_response_to, status_type=ST_FAILURE, message=m)
105 |
106 | elif taxii_content_type == VID_TAXII_XML_10: # It's a TAXII XML 1.0 message
107 | return tm10.get_message_from_xml(response_message, encoding)
108 | elif taxii_content_type == VID_TAXII_XML_11: # It's a TAXII XML 1.1 message
109 | return tm11.get_message_from_xml(response_message, encoding)
110 | elif taxii_content_type == VID_CERT_EU_JSON_10:
111 | return tm10.get_message_from_json(response_message, encoding)
112 | else:
113 | raise ValueError('Unsupported X-TAXII-Content-Type: %s' % taxii_content_type)
114 |
115 |
116 | def get_message_from_httplib_http_response(http_response, in_response_to):
117 | """ This function should not be called by libtaxii users directly. """
118 | if hasattr(http_response, 'getheader'):
119 | taxii_content_type = http_response.getheader('X-TAXII-Content-Type')
120 | _, params = cgi.parse_header(http_response.getheader('Content-Type'))
121 | else:
122 | taxii_content_type = http_response.get('X-TAXII-Content-Type')
123 | _, params = cgi.parse_header(http_response.get('Content-Type'))
124 |
125 | encoding = params.get('charset', 'utf-8')
126 | response_message = six.ensure_text(http_response.read(), errors='replace')
127 |
128 | if taxii_content_type is None: # Treat it as a Failure Status Message, per the spec
129 |
130 | message = []
131 | header_tuples = http_response.getheaders()
132 | for k, v in header_tuples:
133 | message.append(k + ': ' + v + '\r\n')
134 | message.append('\r\n')
135 | message.append(response_message)
136 |
137 | m = ''.join(message)
138 |
139 | return tm11.StatusMessage(message_id='0', in_response_to=in_response_to, status_type=ST_FAILURE, message=m)
140 |
141 | elif taxii_content_type == VID_TAXII_XML_10: # It's a TAXII XML 1.0 message
142 | return tm10.get_message_from_xml(response_message, encoding)
143 | elif taxii_content_type == VID_TAXII_XML_11: # It's a TAXII XML 1.1 message
144 | return tm11.get_message_from_xml(response_message, encoding)
145 | else:
146 | raise ValueError('Unsupported X-TAXII-Content-Type: %s' % taxii_content_type)
147 |
--------------------------------------------------------------------------------
/libtaxii/common.py:
--------------------------------------------------------------------------------
1 | """
2 | Common utility classes and functions used throughout libtaxii.
3 | """
4 |
5 | from operator import attrgetter
6 | import re
7 | import sys
8 | from uuid import uuid4
9 |
10 | import dateutil.parser
11 | from lxml import etree
12 | import six
13 | from six.moves.urllib.parse import urlparse
14 |
15 | try:
16 | import simplejson as json
17 | except ImportError:
18 | import json
19 |
20 | from libtaxii.constants import *
21 |
22 | _XML_PARSER = None
23 |
24 |
25 | def parse(s, allow_file=True, allow_url=False):
26 | """
27 | Uses the default parser to parse a string or file-like object
28 |
29 | :param s: The XML String or File-like object to parse.
30 | :param allow_file: Allow `s` to be a file path.
31 | :param allow_url: Allow `s` to be a URL.
32 | :return: an etree._Element
33 | """
34 | # Do a simple validation that the given string (or URL)
35 | # has no protocol specified. Anything without parseable protocol
36 | # will be interpreted by lxml as string instead or path of external URL.
37 | if not allow_url and isinstance(s, six.string_types):
38 | parsed = urlparse(s)
39 | if parsed.scheme:
40 | raise ValueError('external URLs are not allowed')
41 |
42 | parser = get_xml_parser()
43 |
44 | # parse from string if no external paths allowed
45 | if not allow_file and not allow_url:
46 | return etree.fromstring(s, parser)
47 |
48 | # try to parse from file or string if files are allowed
49 | try:
50 | return etree.parse(s, parser).getroot()
51 | except IOError:
52 | return etree.XML(s, parser)
53 |
54 |
55 | def parse_xml_string(xmlstr):
56 | """Parse an XML string (binary or unicode) with the default parser.
57 |
58 | :param xmlstr: An XML String to parse
59 | :return: an etree._Element
60 | """
61 | if isinstance(xmlstr, six.binary_type):
62 | xmlstr = six.BytesIO(xmlstr)
63 | elif isinstance(xmlstr, six.text_type):
64 | # LXML doesn't accept Unicode strings with an explicit encoding, so
65 | # try to detect and encode to bytes before passing to LXML.
66 | encoding = re.findall(r'encoding="([0-9A-Za-z_\-]+)"', xmlstr[:50], re.I)
67 | # re.findall returns a list of matching strings. We only care about the
68 | # first one.
69 | if encoding:
70 | xmlstr = six.BytesIO(xmlstr.encode(encoding[0]))
71 | else:
72 | xmlstr = six.StringIO(xmlstr)
73 |
74 | return parse(xmlstr, allow_file=True)
75 |
76 |
77 | def get_xml_parser():
78 | """Return the XML parser currently in use.
79 |
80 | If one has not already been set (via :py:func:`set_xml_parser()`), a new
81 | ``etree.XMLParser`` is constructed with ``no_network=True`` and
82 | ``huge_tree=False``.
83 | """
84 | global _XML_PARSER
85 | if _XML_PARSER is None:
86 | _XML_PARSER = etree.XMLParser(
87 | attribute_defaults=False,
88 | dtd_validation=False,
89 | load_dtd=False,
90 | no_network=True,
91 | ns_clean=True,
92 | recover=False,
93 | remove_blank_text=False,
94 | remove_comments=False,
95 | remove_pis=False,
96 | strip_cdata=True,
97 | compact=True,
98 | # collect_ids=True,
99 | resolve_entities=False,
100 | huge_tree=False
101 | )
102 | return _XML_PARSER.copy()
103 |
104 |
105 | def set_xml_parser(xml_parser=None):
106 | """Set the libtaxii.messages XML parser.
107 |
108 | Args:
109 | xml_parser (etree.XMLParser): The parser to use to parse TAXII XML.
110 | """
111 | global _XML_PARSER
112 | _XML_PARSER = xml_parser
113 |
114 |
115 | def parse_datetime_string(datetime_string):
116 | """Parse a string into a :py:class:`datetime.datetime`.
117 |
118 | libtaxii users should not need to use this function directly.
119 | """
120 | if not datetime_string:
121 | return None
122 | return dateutil.parser.parse(datetime_string)
123 |
124 |
125 | def generate_message_id(maxlen=5, version=VID_TAXII_SERVICES_10):
126 | """Generate a TAXII Message ID.
127 |
128 | Args:
129 | maxlen (int): maximum length of the ID, in characters
130 |
131 | Example:
132 | .. code-block:: python
133 |
134 | msg_id = tm11.generate_message_id()
135 | message = tm11.DiscoveryRequest(msg_id)
136 | # Or...
137 | message = tm11.DiscoveryRequest(tm11.generate_message_id())
138 | """
139 | if version == VID_TAXII_SERVICES_10:
140 | message_id = str(uuid4().int % sys.maxsize)
141 | elif version == VID_TAXII_SERVICES_11:
142 | message_id = str(uuid4())
143 | else:
144 | raise ValueError('Unknown TAXII Version: %s. Must be a TAXII Services Version ID!' % version)
145 | return message_id
146 |
147 |
148 | def append_any_content_etree(etree_elt, content):
149 | """
150 | General method for adding content to an etree element. This method can handle:
151 | * etree._ElementTree
152 | * etree._Element
153 | * any python type that can be cast to str
154 | * str
155 |
156 |
157 | :param etree_elt: The etree to append the content to
158 | :param content: The content to append
159 | :return: The etree_elt
160 | """
161 |
162 | if isinstance(content, etree._ElementTree): # If content is an element tree, append the root element
163 | etree_elt.append(content.getroot())
164 | return etree_elt
165 |
166 | if isinstance(content, etree._Element): # If content is an element, append it
167 | etree_elt.append(content)
168 | return etree_elt
169 |
170 | if not isinstance(content, six.string_types): # If content is a non-string, cast it to string and set etree_elt.text
171 | etree_elt.text = str(content)
172 | return etree_elt
173 |
174 | # If content is a string, need to check if it's XML or not
175 | try:
176 | etree_elt.append(etree.XML(content, get_xml_parser()))
177 | except etree.XMLSyntaxError:
178 | etree_elt.text = content
179 |
180 | return etree_elt
181 |
182 |
183 | def gen_filename(collection_name, format_part, date_string, extension):
184 | """
185 | Creates a filename based on various properties of a Poll Request and Content Block
186 |
187 | :param collection_name: The collection name
188 | :param format_part: The format part (e.g., '_STIX_10_')
189 | :param date_string: A datestring
190 | :param extension: The file extension to use
191 | :return: A string containing the generated filename
192 | """
193 | if six.PY3:
194 | return (collection_name.lstrip(".") +
195 | format_part +
196 | re.sub(r"[^a-zA-Z0-9]", "_", date_string) + extension
197 | ).translate('/\\:*?"<>|')
198 | else:
199 | return (collection_name.lstrip(".") +
200 | format_part +
201 | re.sub(r"[^a-zA-Z0-9]", "_", date_string) + extension
202 | ).translate(None, '/\\:*?"<>|')
203 |
204 |
205 | class TAXIIBase(object):
206 |
207 | """
208 | Base class for all TAXII Messages and Message component types.
209 |
210 | libtaxii users should not need to use this class directly.
211 | """
212 |
213 | @property
214 | def sort_key(self):
215 | """
216 | This property allows list of TAXII objects to be compared efficiently.
217 | The __eq__ method uses this property to sort the lists before
218 | comparisons are made.
219 |
220 | Subclasses must implement this property.
221 | """
222 | raise NotImplementedError()
223 |
224 | def to_etree(self):
225 | """Create an etree representation of this class.
226 |
227 | Subclasses must implement this method.
228 | """
229 | raise NotImplementedError()
230 |
231 | def to_dict(self):
232 | """Create a dictionary representation of this class.
233 |
234 | Subclasses must implement this method.
235 | """
236 | raise NotImplementedError()
237 |
238 | def to_json(self):
239 | """Create a JSON object of this class.
240 |
241 | Assumes any binary content will be UTF-8 encoded.
242 | """
243 | content_dict = self.to_dict()
244 |
245 | _decode_binary_fields(content_dict)
246 |
247 | return json.dumps(content_dict)
248 |
249 | def to_xml(self, pretty_print=False):
250 | """Create an XML representation of this class.
251 |
252 | Subclasses should not need to implement this method.
253 | """
254 | return etree.tostring(self.to_etree(), pretty_print=pretty_print, encoding='utf-8')
255 |
256 | def to_text(self, line_prepend=''):
257 | """Create a nice looking (this is a subjective term!)
258 | textual representation of this class. Subclasses should
259 | implement this method.
260 |
261 | Note that this is just a convenience method for making
262 | TAXII Messages nice to read for humans and may change
263 | drastically in future versions of libtaxii.
264 | """
265 | raise NotImplementedError()
266 |
267 | @classmethod
268 | def from_etree(cls, src_etree):
269 | """Create an instance of this class from an etree.
270 |
271 | Subclasses must implement this method.
272 | """
273 | raise NotImplementedError()
274 |
275 | @classmethod
276 | def from_dict(cls, d):
277 | """Create an instance of this class from a dictionary.
278 |
279 | Subclasses must implement this method.
280 | """
281 | raise NotImplementedError()
282 |
283 | @classmethod
284 | def from_xml(cls, xml):
285 | """Create an instance of this class from XML.
286 |
287 | Subclasses should not need to implement this method.
288 | """
289 | etree_xml = parse_xml_string(xml)
290 | return cls.from_etree(etree_xml)
291 |
292 | # Just noting that there is not a from_text() method. I also
293 | # don't think there will ever be one.
294 |
295 | def __str__(self):
296 | return self.to_xml(pretty_print=True)
297 |
298 | def __eq__(self, other, debug=False):
299 | """
300 | Generic method used to check equality of objects of any TAXII type.
301 |
302 | Also allows for ``print``-based debugging output showing differences.
303 |
304 | In order for subclasses to use this function, they must meet the
305 | following criteria:
306 | 1. All class properties start with one underscore.
307 | 2. The sort_key property is implemented.
308 |
309 | Args:
310 | self (object): this object
311 | other (object): the object to compare ``self`` against.
312 | debug (bool): Whether or not to print debug statements as the
313 | equality comparison is performed.
314 | """
315 | if other is None:
316 | if debug:
317 | print('other was None!')
318 | return False
319 |
320 | if self.__class__.__name__ != other.__class__.__name__:
321 | if debug:
322 | print('class names not equal: %s != %s' % (self.__class__.__name__, other.__class__.__name__))
323 | return False
324 |
325 | # Get all member properties that start with '_'
326 | members = [attr for attr in vars(self) if attr.startswith('_') and not attr.startswith('__')]
327 | for member in members:
328 | if debug:
329 | print('member name: %s' % member)
330 | self_value = getattr(self, member)
331 | other_value = getattr(other, member)
332 |
333 | if isinstance(self_value, TAXIIBase):
334 | # A debuggable equals comparison can be made
335 | eq = self_value.__eq__(other_value, debug)
336 | elif isinstance(self_value, list):
337 | # We have lists to compare
338 | if len(self_value) != len(other_value):
339 | # Lengths not equal
340 | member = member + ' lengths'
341 | self_value = len(self_value)
342 | other_value = len(other_value)
343 | eq = False
344 | elif len(self_value) == 0:
345 | # Both lists are of size 0, and therefore equal
346 | eq = True
347 | else:
348 | # Equal sized, non-0 length lists. The list might contain
349 | # TAXIIBase objects, or it might not. Peek at the first
350 | # item to see whether it is a TAXIIBase object or not.
351 | if isinstance(self_value[0], TAXIIBase):
352 | # All TAXIIBase objects have the 'sort_key' property implemented
353 | self_value = sorted(self_value, key=attrgetter('sort_key'))
354 | other_value = sorted(other_value, key=attrgetter('sort_key'))
355 | for self_item, other_item in six.moves.zip(self_value, other_value):
356 | # Compare the ordered lists element by element
357 | eq = self_item.__eq__(other_item, debug)
358 | else:
359 | # Assume they don't... just do a set comparison
360 | eq = set(self_value) == set(other_value)
361 | elif isinstance(self_value, dict):
362 | # Dictionary to compare
363 | if len(set(self_value.keys()) - set(other_value.keys())) != 0:
364 | if debug:
365 | print('dict keys not equal: %s != %s' % (self_value, other_value))
366 | eq = False
367 | for k, v in six.iteritems(self_value):
368 | if other_value[k] != v:
369 | if debug:
370 | print('dict values not equal: %s != %s' % (v, other_value[k]))
371 | eq = False
372 | eq = True
373 | elif isinstance(self_value, etree._Element):
374 | # Non-TAXII etree element (i.e. STIX)
375 | eq = (etree.tostring(self_value, encoding='utf-8') == etree.tostring(other_value, encoding='utf-8'))
376 | else:
377 | # Do a direct comparison
378 | eq = (self_value == other_value)
379 |
380 | # TODO: is this duplicate?
381 | if not eq:
382 | if debug:
383 | print('%s was not equal: %s != %s' % (member, self_value, other_value))
384 | return False
385 |
386 | return True
387 |
388 | def __ne__(self, other, debug=False):
389 | return not self.__eq__(other, debug)
390 |
391 |
392 | def get_required(etree_xml, xpath, ns_map):
393 | elements = etree_xml.xpath(xpath, namespaces=ns_map)
394 | if len(elements) == 0:
395 | raise ValueError('Element "%s" is required' % xpath)
396 | return elements[0]
397 |
398 |
399 | def get_optional(etree_xml, xpath, ns_map):
400 | try:
401 | return get_required(etree_xml, xpath, ns_map)
402 | except ValueError:
403 | pass
404 |
405 |
406 | def get_optional_text(etree_xml, xpath, ns_map):
407 | try:
408 | return get_required(etree_xml, xpath, ns_map).text
409 | except ValueError:
410 | pass
411 |
412 |
413 | def _decode_binary_fields(dict_obj):
414 | """Given a dict, decode any binary values, assuming UTF-8 encoding.
415 | Will recurse into nested dicts.
416 | Modifies the values in-place.
417 | """
418 | for key, value in dict_obj.items():
419 |
420 | if isinstance(value, six.binary_type):
421 | dict_obj[key] = value.decode('utf-8')
422 |
423 | elif isinstance(value, dict):
424 | _decode_binary_fields(value)
425 |
426 |
427 | def stringify_content(content):
428 | """Always a string or raises an error.
429 | Returns the string representation and whether the data is XML.
430 | """
431 | # If it's an etree, it's definitely XML
432 | if isinstance(content, etree._ElementTree):
433 | return content.getroot(), True
434 |
435 | if isinstance(content, etree._Element):
436 | return content, True
437 |
438 | if hasattr(content, 'read'): # The content is file-like
439 | try: # Try to parse as XML
440 | xml = parse(content, allow_file=True)
441 | return xml, True
442 | except etree.XMLSyntaxError: # Content is not well-formed XML; just treat as a string
443 | return content.read(), False
444 | else: # The Content is not file-like
445 | try: # Attempt to parse string as XML
446 | xml = parse_xml_string(content)
447 | return xml, True
448 | except etree.XMLSyntaxError: # Content is not well-formed XML; just treat as a string
449 | if isinstance(content, six.string_types): # It's a string of some kind, unicode or otherwise
450 | return content, False
451 | else: # It's some other datatype that needs casting to string
452 | return str(content), False
453 |
--------------------------------------------------------------------------------
/libtaxii/constants.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2017, The MITRE Corporation
2 | # For license information, see the LICENSE.txt file
3 |
4 | #: Namespace map of namespaces libtaxii knows about
5 | NS_MAP = {
6 | 'taxii': 'http://taxii.mitre.org/messages/taxii_xml_binding-1',
7 | 'taxii_11': 'http://taxii.mitre.org/messages/taxii_xml_binding-1.1',
8 | 'tdq': 'http://taxii.mitre.org/query/taxii_default_query-1',
9 | }
10 |
11 | #: alias for NS_MAP for backward compatibility
12 | ns_map = NS_MAP
13 |
14 | #: Constant identifying a Status Message
15 | MSG_STATUS_MESSAGE = 'Status_Message'
16 | #: Constant identifying a Discovery Request Message
17 | MSG_DISCOVERY_REQUEST = 'Discovery_Request'
18 | #: Constant identifying a Discovery Response Message
19 | MSG_DISCOVERY_RESPONSE = 'Discovery_Response'
20 | #: Constant identifying a Feed Information Request Message
21 | MSG_FEED_INFORMATION_REQUEST = 'Feed_Information_Request'
22 | #: Constant identifying a Feed Information Response Message
23 | MSG_FEED_INFORMATION_RESPONSE = 'Feed_Information_Response'
24 | #: Constant identifying a Subscription Management Request Message
25 | MSG_MANAGE_FEED_SUBSCRIPTION_REQUEST = 'Subscription_Management_Request'
26 | #: Constant identifying a Subscription Management Response Message
27 | MSG_MANAGE_FEED_SUBSCRIPTION_RESPONSE = 'Subscription_Management_Response'
28 | #: Constant identifying a Poll Request Message
29 | MSG_POLL_REQUEST = 'Poll_Request'
30 | #: Constant identifying a Poll Response Message
31 | MSG_POLL_RESPONSE = 'Poll_Response'
32 | #: Constant identifying a Inbox Message
33 | MSG_INBOX_MESSAGE = 'Inbox_Message'
34 |
35 | #: TAXII 1.0 Message Types
36 | MSG_TYPES_10 = (MSG_STATUS_MESSAGE, MSG_DISCOVERY_REQUEST, MSG_DISCOVERY_RESPONSE,
37 | MSG_FEED_INFORMATION_REQUEST, MSG_FEED_INFORMATION_RESPONSE,
38 | MSG_MANAGE_FEED_SUBSCRIPTION_REQUEST,
39 | MSG_MANAGE_FEED_SUBSCRIPTION_RESPONSE, MSG_POLL_REQUEST,
40 | MSG_POLL_RESPONSE, MSG_INBOX_MESSAGE)
41 |
42 | # New Message Types in TAXII 1.1
43 |
44 | #: Constant identifying a Status Message
45 | MSG_POLL_FULFILLMENT_REQUEST = 'Poll_Fulfillment'
46 | #: Constant identifying a Collection Information Request
47 | MSG_COLLECTION_INFORMATION_REQUEST = 'Collection_Information_Request'
48 | #: Constant identifying a Collection Information Response
49 | MSG_COLLECTION_INFORMATION_RESPONSE = 'Collection_Information_Response'
50 | #: Constant identifying a Subscription Request
51 | MSG_MANAGE_COLLECTION_SUBSCRIPTION_REQUEST = 'Subscription_Management_Request'
52 | #: Constant identifying a Subscription Response
53 | MSG_MANAGE_COLLECTION_SUBSCRIPTION_RESPONSE = 'Subscription_Management_Response'
54 |
55 | #: Tuple of all TAXII 1.1 Message Types
56 | MSG_TYPES_11 = (MSG_STATUS_MESSAGE, MSG_DISCOVERY_REQUEST, MSG_DISCOVERY_RESPONSE,
57 | MSG_COLLECTION_INFORMATION_REQUEST, MSG_COLLECTION_INFORMATION_RESPONSE,
58 | MSG_MANAGE_COLLECTION_SUBSCRIPTION_REQUEST,
59 | MSG_MANAGE_COLLECTION_SUBSCRIPTION_RESPONSE, MSG_POLL_REQUEST,
60 | MSG_POLL_RESPONSE, MSG_INBOX_MESSAGE, MSG_POLL_FULFILLMENT_REQUEST)
61 |
62 | # TAXII 1.0 Status Types
63 |
64 | #: Constant identifying a Status Type of Bad Message
65 | ST_BAD_MESSAGE = 'BAD_MESSAGE'
66 | #: Constant identifying a Status Type of Denied
67 | ST_DENIED = 'DENIED'
68 | #: Constant identifying a Status Type of Failure
69 | ST_FAILURE = 'FAILURE'
70 | #: Constant identifying a Status Type of Not Found
71 | ST_NOT_FOUND = 'NOT_FOUND'
72 | #: Constant identifying a Status Type of Polling Unsupported
73 | ST_POLLING_UNSUPPORTED = 'POLLING_UNSUPPORTED'
74 | #: Constant identifying a Status Type of Retry
75 | ST_RETRY = 'RETRY'
76 | #: Constant identifying a Status Type of Success
77 | ST_SUCCESS = 'SUCCESS'
78 | #: Constant identifying a Status Type of Unauthorized
79 | ST_UNAUTHORIZED = 'UNAUTHORIZED'
80 | #: Constant identifying a Status Type of Unsupported Message Binding
81 | ST_UNSUPPORTED_MESSAGE_BINDING = 'UNSUPPORTED_MESSAGE'
82 | #: Constant identifying a Status Type of Unsupported Content Binding
83 | ST_UNSUPPORTED_CONTENT_BINDING = 'UNSUPPORTED_CONTENT'
84 | #: Constant identifying a Status Type of Unsupported Protocol Binding
85 | ST_UNSUPPORTED_PROTOCOL = 'UNSUPPORTED_PROTOCOL'
86 |
87 | #: Tuple of all TAXII 1.0 Status Types
88 | ST_TYPES_10 = (ST_BAD_MESSAGE, ST_DENIED, ST_FAILURE, ST_NOT_FOUND,
89 | ST_POLLING_UNSUPPORTED, ST_RETRY, ST_SUCCESS, ST_UNAUTHORIZED,
90 | ST_UNSUPPORTED_MESSAGE_BINDING, ST_UNSUPPORTED_CONTENT_BINDING,
91 | ST_UNSUPPORTED_PROTOCOL)
92 |
93 | # New Status Types in TAXII 1.1
94 |
95 | #: Constant identifying a Status Type of Asynchronous Poll Error
96 | ST_ASYNCHRONOUS_POLL_ERROR = 'ASYNCHRONOUS_POLL_ERROR'
97 | #: Constant identifying a Status Type of Destination Collection Error
98 | ST_DESTINATION_COLLECTION_ERROR = 'DESTINATION_COLLECTION_ERROR'
99 | #: Constant identifying a Status Type of Invalid Response Part
100 | ST_INVALID_RESPONSE_PART = 'INVALID_RESPONSE_PART'
101 | #: Constant identifying a Status Type of Network Error
102 | ST_NETWORK_ERROR = 'NETWORK_ERROR'
103 | #: Constant identifying a Status Type of Pending
104 | ST_PENDING = 'PENDING'
105 | #: Constant identifying a Status Type of Unsupported Query Format
106 | ST_UNSUPPORTED_QUERY = 'UNSUPPORTED_QUERY'
107 |
108 | #: Tuple of all TAXII 1.1 Status types
109 | ST_TYPES_11 = (ST_ASYNCHRONOUS_POLL_ERROR, ST_BAD_MESSAGE, ST_DENIED,
110 | ST_DESTINATION_COLLECTION_ERROR, ST_FAILURE, ST_INVALID_RESPONSE_PART,
111 | ST_NETWORK_ERROR, ST_NOT_FOUND, ST_PENDING, ST_POLLING_UNSUPPORTED,
112 | ST_RETRY, ST_SUCCESS, ST_UNAUTHORIZED, ST_UNSUPPORTED_MESSAGE_BINDING,
113 | ST_UNSUPPORTED_CONTENT_BINDING, ST_UNSUPPORTED_PROTOCOL,
114 | ST_UNSUPPORTED_QUERY)
115 |
116 | # TAXII 1.0 Action Types
117 |
118 | #: Constant identifying an Action of Subscribe
119 | ACT_SUBSCRIBE = 'SUBSCRIBE'
120 | #: Constant identifying an Action of Unsubscribe
121 | ACT_UNSUBSCRIBE = 'UNSUBSCRIBE'
122 | #: Constant identifying an Action of Status
123 | ACT_STATUS = 'STATUS'
124 |
125 | #: Tuple of all TAXII 1.0 Action Types
126 | ACT_TYPES_10 = (ACT_SUBSCRIBE, ACT_UNSUBSCRIBE, ACT_STATUS)
127 |
128 | #: Constant identifying an Action of Pause
129 | ACT_PAUSE = 'PAUSE'
130 | #: Constant identifying an Action of Resume
131 | ACT_RESUME = 'RESUME'
132 |
133 | #: Tuple of all TAXII 1.1 Action types
134 | ACT_TYPES_11 = (ACT_SUBSCRIBE, ACT_PAUSE, ACT_RESUME, ACT_UNSUBSCRIBE, ACT_STATUS)
135 |
136 | # TAXII 1.0 Service Types
137 |
138 | #: Constant identifying a Service Type of Inbox
139 | SVC_INBOX = 'INBOX'
140 | #: Constant identifying a Service Type of Poll
141 | SVC_POLL = 'POLL'
142 | #: Constant identifying a Service Type of Feed Management
143 | SVC_FEED_MANAGEMENT = 'FEED_MANAGEMENT'
144 | #: Constant identifying a Service Type of Discovery
145 | SVC_DISCOVERY = 'DISCOVERY'
146 |
147 | #: Tuple of all TAXII 1.0 Service Types
148 | SVC_TYPES_10 = (SVC_INBOX, SVC_POLL, SVC_FEED_MANAGEMENT, SVC_DISCOVERY)
149 |
150 | # Renamed Status Types in TAXII 1.1
151 | #: Constant identifying a Service Type of Collection Management.
152 | #: "Feed Management" was renamed to "Collection Management" in TAXII 1.1.
153 | SVC_COLLECTION_MANAGEMENT = 'COLLECTION_MANAGEMENT'
154 |
155 | #: Tuple of all TAXII 1.1 Service Types
156 | SVC_TYPES_11 = (SVC_INBOX, SVC_POLL, SVC_COLLECTION_MANAGEMENT, SVC_DISCOVERY)
157 |
158 | # TAXII 1.1 Subscription Statuses
159 |
160 | #: Subscription Status of Active
161 | SS_ACTIVE = 'ACTIVE'
162 | #: Subscription Status of Paused
163 | SS_PAUSED = 'PAUSED'
164 | #: Subscription Status of Unsubscribed
165 | SS_UNSUBSCRIBED = 'UNSUBSCRIBED'
166 |
167 | #: Tuple of all TAXII 1.1 Subscription Statues
168 | SS_TYPES_11 = (SS_ACTIVE, SS_PAUSED, SS_UNSUBSCRIBED)
169 |
170 | # TAXII 1.1 Response Types
171 |
172 | #: Constant identifying a response type of Full
173 | RT_FULL = 'FULL'
174 | #: Constant identifying a response type of Count only
175 | RT_COUNT_ONLY = 'COUNT_ONLY'
176 |
177 | #: Tuple of all TAXII 1.1 Response Types
178 | RT_TYPES_11 = (RT_FULL, RT_COUNT_ONLY)
179 |
180 | # TAXII 1.1 Response Types
181 |
182 | #: Constant identifying a collection type of Data Feed
183 | CT_DATA_FEED = 'DATA_FEED'
184 | #: Constant identifying a collection type of Data Set
185 | CT_DATA_SET = 'DATA_SET'
186 |
187 | #: Tuple of all TAXII 1.1 Collection Types
188 | CT_TYPES_11 = (CT_DATA_FEED, CT_DATA_SET)
189 |
190 | # TAXII 1.1 Status Detail Keys
191 |
192 | #: Constant Identifying the Acceptable Destination Status Detail
193 | SD_ACCEPTABLE_DESTINATION = 'ACCEPTABLE_DESTINATION'
194 | #: Constant Identifying the Max Part Number Status Detail
195 | SD_MAX_PART_NUMBER = 'MAX_PART_NUMBER'
196 | #: Constant Identifying the Item Status Detail
197 | SD_ITEM = 'ITEM'
198 | #: Constant Identifying the Estimated Wait Status Detail
199 | SD_ESTIMATED_WAIT = 'ESTIMATED_WAIT'
200 | #: Constant Identifying the Result ID Status Detail
201 | SD_RESULT_ID = 'RESULT_ID'
202 | #: Constant Identifying the Will Push Status Detail
203 | SD_WILL_PUSH = 'WILL_PUSH'
204 | #: Constant Identifying the Supported Binding Status Detail
205 | SD_SUPPORTED_BINDING = 'SUPPORTED_BINDING'
206 | #: Constant Identifying the Supported Content Status Detail
207 | SD_SUPPORTED_CONTENT = 'SUPPORTED_CONTENT'
208 | #: Constant Identifying the Supported Protocol Status Detail
209 | SD_SUPPORTED_PROTOCOL = 'SUPPORTED_PROTOCOL'
210 | #: Constant Identifying the Supported Query Status Detail
211 | SD_SUPPORTED_QUERY = 'SUPPORTED_QUERY'
212 |
213 | #: Tuple of all TAXII 1.1 Status Detail Keys
214 | SD_TYPES_11 = (SD_ACCEPTABLE_DESTINATION, SD_MAX_PART_NUMBER, SD_ITEM,
215 | SD_ESTIMATED_WAIT, SD_RESULT_ID, SD_WILL_PUSH,
216 | SD_SUPPORTED_BINDING, SD_SUPPORTED_CONTENT, SD_SUPPORTED_PROTOCOL,
217 | SD_SUPPORTED_QUERY)
218 |
219 | #: (For TAXII Default Query) Constant identifying supported Capability Modules
220 | SD_CAPABILITY_MODULE = 'CAPABILITY_MODULE'
221 | #: (For TAXII Default Query) Constant identifying Preferred Scopes
222 | SD_PREFERRED_SCOPE = 'PREFERRED_SCOPE'
223 | #: (For TAXII Default Query) Constant identifying Allowed Scopes
224 | SD_ALLOWED_SCOPE = 'ALLOWED_SCOPE'
225 | #: (For TAXII Default Query) Constant identifying supported Targeting Expression IDs
226 | SD_TARGETING_EXPRESSION_ID = 'TARGETING_EXPRESSION_ID'
227 |
228 | #: Format ID for this version of TAXII Default Query
229 | FID_TAXII_DEFAULT_QUERY_10 = 'urn:taxii.mitre.org:query:default:1.0'
230 |
231 | # Capability Module IDs
232 | #: Capability Module ID for Core
233 | CM_CORE = 'urn:taxii.mitre.org:query:capability:core-1'
234 | #: Capability Module ID for Regex
235 | CM_REGEX = 'urn:taxii.mitre.org:query:capability:regex-1'
236 | #: Capability Module ID for Timestamp
237 | CM_TIMESTAMP = 'urn:taxii.mitre.org:query:capability:timestamp-1'
238 |
239 | #: Tuple of all capability modules defined in TAXII Default Query 1.0
240 | CM_IDS = (CM_CORE, CM_REGEX, CM_TIMESTAMP)
241 |
242 | # Operators
243 | #: Operator OR
244 | OP_OR = 'OR'
245 | #: Operator AND
246 | OP_AND = 'AND'
247 |
248 | #: Tuple of all operators
249 | OP_TYPES = (OP_OR, OP_AND)
250 |
251 |
252 | #: Status Type indicating an unsupported capability module
253 | ST_UNSUPPORTED_CAPABILITY_MODULE = 'UNSUPPORTED_CAPABILITY_MODULE'
254 | #: Status Type indicating an unsupported targeting expression
255 | ST_UNSUPPORTED_TARGETING_EXPRESSION = 'UNSUPPORTED_TARGETING_EXPRESSION'
256 | #: Status Type indicating an unsupported targeting expression id
257 | ST_UNSUPPORTED_TARGETING_EXPRESSION_ID = 'UNSUPPORTED_TARGETING_EXPRESSION_ID'
258 |
259 | #: Parameter name: value
260 | P_VALUE = 'value'
261 | #: Parameter name: match_type
262 | P_MATCH_TYPE = 'match_type'
263 | #: Parameter name: case_sensitive
264 | P_CASE_SENSITIVE = 'case_sensitive'
265 |
266 | #: Tuple of all parameter names
267 | P_NAMES = (P_VALUE, P_MATCH_TYPE, P_CASE_SENSITIVE)
268 |
269 | #: Relationship name: equals
270 | R_EQUALS = 'equals'
271 | #: Relationship name: not_requals
272 | R_NOT_EQUALS = 'not_equals'
273 | #: Relationship name: greater_than
274 | R_GREATER_THAN = 'greater_than'
275 | #: Relationship name: greater_than_or_equal
276 | R_GREATER_THAN_OR_EQUAL = 'greater_than_or_equal'
277 | #: Relationship name: less_than
278 | R_LESS_THAN = 'less_than'
279 | #: Relationship name: less_than_or_equal
280 | R_LESS_THAN_OR_EQUAL = 'less_than_or_equal'
281 | #: Relationship name: does_not_exist
282 | R_DOES_NOT_EXIST = 'does_not_exist'
283 | #: Relationship name: exists
284 | R_EXISTS = 'exists'
285 | #: Relationship name: begins_with
286 | R_BEGINS_WITH = 'begins_with'
287 | #: Relationship name: ends_with
288 | R_ENDS_WITH = 'ends_with'
289 | #: Relationship name: contains
290 | R_CONTAINS = 'contains'
291 | #: Relationship name: matches
292 | R_MATCHES = 'matches'
293 |
294 | #: Tuple of all relationship names
295 | R_NAMES = (R_EQUALS, R_NOT_EQUALS, R_GREATER_THAN,
296 | R_GREATER_THAN_OR_EQUAL, R_LESS_THAN,
297 | R_LESS_THAN_OR_EQUAL, R_DOES_NOT_EXIST,
298 | R_EXISTS, R_BEGINS_WITH, R_ENDS_WITH,
299 | R_CONTAINS, R_MATCHES)
300 |
301 | # TAXII Version IDs #
302 |
303 | #: Version ID for the TAXII Services Specification 1.0
304 | VID_TAXII_SERVICES_10 = 'urn:taxii.mitre.org:services:1.0'
305 | #: Version ID for the TAXII Services Specification 1.1
306 | VID_TAXII_SERVICES_11 = 'urn:taxii.mitre.org:services:1.1'
307 | #: Version ID for the TAXII XML Message Binding Specification 1.0
308 | VID_TAXII_XML_10 = 'urn:taxii.mitre.org:message:xml:1.0'
309 | #: Version ID for the TAXII XML Message Binding Specification 1.1
310 | VID_TAXII_XML_11 = 'urn:taxii.mitre.org:message:xml:1.1'
311 | #: Version ID for the TAXII HTTP Protocol Binding Specification 1.0
312 | VID_TAXII_HTTP_10 = 'urn:taxii.mitre.org:protocol:http:1.0'
313 | #: Version ID for the TAXII HTTPS Protocol Binding Specification 1.0
314 | VID_TAXII_HTTPS_10 = 'urn:taxii.mitre.org:protocol:https:1.0'
315 |
316 | # Third Party Version IDs
317 | #: Version ID for the CERT EU JSON Message Binding
318 | VID_CERT_EU_JSON_10 = 'urn:cert.europa.eu:message:json:1.0'
319 |
320 |
321 | # TAXII Content Bindings #
322 |
323 | #: Content Binding ID for STIX XML 1.0
324 | CB_STIX_XML_10 = 'urn:stix.mitre.org:xml:1.0'
325 | #: Content Binding ID for STIX XML 1.0.1
326 | CB_STIX_XML_101 = 'urn:stix.mitre.org:xml:1.0.1'
327 | #: Content Binding ID for STIX XML 1.1
328 | CB_STIX_XML_11 = 'urn:stix.mitre.org:xml:1.1'
329 | #: Content Binding ID for STIX XML 1.1.1
330 | CB_STIX_XML_111 = 'urn:stix.mitre.org:xml:1.1.1'
331 | #: Content Binding ID for STIX XML 1.2
332 | CB_STIX_XML_12 = 'urn:stix.mitre.org:xml:1.2'
333 | #: Content Binding ID for CAP 1.1
334 | CB_CAP_11 = 'urn:oasis:names:tc:emergency:cap:1.1'
335 | #: Content Binding ID for XML Encryption
336 | CB_XENC_122002 = 'http://www.w3.org/2001/04/xmlenc#'
337 | #: Content Binding ID for SMIME
338 | CB_SMIME = 'application/x-pkcs7-mime'
339 |
340 | STD_INDENT = ' ' # A "Standard Indent" to use for to_text() methods
341 |
--------------------------------------------------------------------------------
/libtaxii/messages.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2017, The MITRE Corporation
2 | # For license information, see the LICENSE.txt file
3 |
4 | """Backwards compatibility for TAXII 1.0.
5 |
6 | All TAXII Message classes used to be in this file. Since TAXII 1.1 support
7 | was added (in messages_11.py), the contents of this file were moved to
8 | messages_10.py. This file allows existing code (referring to libtaxii.messages)
9 | to continue working as before.
10 | """
11 |
12 |
13 | from libtaxii.messages_10 import *
14 |
--------------------------------------------------------------------------------
/libtaxii/scripts/collection_information_client.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright (c) 2017, The MITRE Corporation
4 | # For license information, see the LICENSE.txt file
5 |
6 | import libtaxii.messages_11 as tm11
7 | from libtaxii.scripts import TaxiiScript
8 |
9 |
10 | class CollectionInformationClient11Script(TaxiiScript):
11 | """Collection Information Request Client"""
12 |
13 | parser_description = \
14 | 'The TAXII 1.1 Collection Information Client sends a Collection Information Request ' \
15 | 'to a TAXII Server and then prints the resulting Collection Information Response to ' \
16 | 'standard out.'
17 |
18 | path = '/taxii-data'
19 |
20 | def create_request_message(self, args):
21 | message_id = tm11.generate_message_id()
22 | return tm11.CollectionInformationRequest(message_id)
23 |
24 |
25 | def main():
26 | """Send a Collection Information Request to a Taxii 1.0 Service"""
27 | script = CollectionInformationClient11Script()
28 | script()
29 |
30 | if __name__ == "__main__":
31 | main()
32 |
--------------------------------------------------------------------------------
/libtaxii/scripts/discovery_client.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright (c) 2017, The MITRE Corporation
4 | # For license information, see the LICENSE.txt file
5 |
6 | from libtaxii.scripts import TaxiiScript
7 | import libtaxii.messages_11 as tm11
8 | import libtaxii.taxii_default_query as tdq
9 |
10 |
11 | class DiscoveryClient11Script(TaxiiScript):
12 | parser_description = 'The TAXII 1.1 Discovery Client sends a Discovery Request message to a TAXII Server and ' \
13 | 'prints out the Discovery Response message to standard out.'
14 | path = '/taxii-discovery-service'
15 |
16 | def create_request_message(self, args):
17 | return tm11.DiscoveryRequest(message_id=tm11.generate_message_id())
18 |
19 |
20 | def main():
21 | script = DiscoveryClient11Script()
22 | script()
23 |
24 | if __name__ == "__main__":
25 | main()
26 |
--------------------------------------------------------------------------------
/libtaxii/scripts/discovery_client_10.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright (c) 2017, The MITRE Corporation
4 | # For license information, see the LICENSE.txt file
5 |
6 | from libtaxii.scripts import TaxiiScript
7 | import libtaxii.messages_10 as tm10
8 | from libtaxii.common import generate_message_id
9 | from libtaxii.constants import *
10 |
11 | class DiscoveryClient10Script(TaxiiScript):
12 | taxii_version = VID_TAXII_XML_10
13 | parser_description = 'The TAXII 1.0 Discovery Client sends a Discovery Request message to a TAXII Server and ' \
14 | 'prints out the Discovery Response message to standard out.'
15 | path = '/taxii-discovery-service'
16 |
17 | def create_request_message(self, args):
18 | return tm10.DiscoveryRequest(message_id=generate_message_id())
19 |
20 |
21 | def main():
22 | script = DiscoveryClient10Script()
23 | script()
24 |
25 | if __name__ == "__main__":
26 | main()
27 |
--------------------------------------------------------------------------------
/libtaxii/scripts/feed_information_client_10.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright (c) 2017, The MITRE Corporation
4 | # For license information, see the LICENSE.txt file
5 |
6 | import libtaxii.messages_10 as tm10
7 | from libtaxii.scripts import TaxiiScript
8 | from libtaxii.constants import VID_TAXII_XML_10
9 |
10 |
11 | class FeedInformationClient10Script(TaxiiScript):
12 | """Feed Information Request Client"""
13 | taxii_version = VID_TAXII_XML_10
14 | parser_description = \
15 | 'The TAXII 1.0 Feed Information Client sends a Feed Information ' \
16 | 'Request message to a TAXII Server and prints the Feed Information ' \
17 | 'Response message to standard out.'
18 |
19 | path = '/taxii-data'
20 |
21 | def create_request_message(self, args):
22 | message_id = tm10.generate_message_id()
23 | return tm10.FeedInformationRequest(message_id)
24 |
25 |
26 | def main():
27 | """Send a Feed Information Request to a Taxii 1.0 Service"""
28 | script = FeedInformationClient10Script()
29 | script()
30 |
31 | if __name__ == "__main__":
32 | main()
33 |
--------------------------------------------------------------------------------
/libtaxii/scripts/fulfillment_client.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright (c) 2017, The MITRE Corporation
4 | # For license information, see the LICENSE.txt file
5 |
6 | import libtaxii.messages_11 as tm11
7 | from libtaxii.scripts import TaxiiScript, add_poll_response_args
8 | from libtaxii.constants import *
9 |
10 |
11 | class FulfillmentClient11Script(TaxiiScript):
12 | parser_description = 'The TAXII 1.1 Poll Fulfillment Client sends a Poll Fulfillment Request to a TAXII Server ' \
13 | 'and prints out the Poll Response to standard out, saving the Content Blocks to disk (' \
14 | 'depending on command line arguments).'
15 | path = '/taxii-data'
16 |
17 | def get_arg_parser(self, *args, **kwargs):
18 | parser = super(FulfillmentClient11Script, self).get_arg_parser(*args, **kwargs)
19 | parser.add_argument("--collection",
20 | dest="collection",
21 | default="default",
22 | help="Data Collection that this Fulfillment request applies to. Defaults to 'default'.")
23 | parser.add_argument("--result-id",
24 | dest="result_id",
25 | required=True, help="The result_id being requested.")
26 | parser.add_argument("--result-part-number",
27 | dest="result_part_number",
28 | type=int,
29 | default=1,
30 | help="The part number being requested. Defaults to '1'.")
31 | add_poll_response_args(parser)
32 | return parser
33 |
34 | def create_request_message(self, args):
35 | poll_fulf_req = tm11.PollFulfillmentRequest(message_id=tm11.generate_message_id(),
36 | collection_name=args.collection,
37 | result_id=args.result_id,
38 | result_part_number=args.result_part_number)
39 | return poll_fulf_req
40 |
41 | def handle_response(self, response, args):
42 | super(FulfillmentClient11Script, self).handle_response(response, args)
43 | if response.message_type == MSG_POLL_RESPONSE:
44 | if response.more:
45 | print("This response has More=True, to request additional parts, use the following command:")
46 | print(" fulfillment_client --collection %s --result-id %s --result-part-number %s\r\n" % \
47 | (response.collection_name, response.result_id, response.result_part_number + 1))
48 | self.write_cbs_from_poll_response_11(response, dest_dir=args.dest_dir, write_type_=args.write_type)
49 |
50 |
51 | def main():
52 | script = FulfillmentClient11Script()
53 | script()
54 |
55 | if __name__ == "__main__":
56 | main()
57 |
--------------------------------------------------------------------------------
/libtaxii/scripts/inbox_client.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright (c) 2017, The MITRE Corporation
4 | # For license information, see the LICENSE.txt file
5 |
6 | from libtaxii.scripts import TaxiiScript
7 | import libtaxii.messages_11 as tm11
8 | from libtaxii.constants import *
9 |
10 | class InboxClient11Script(TaxiiScript):
11 | parser_description = 'The TAXII 1.1 Inbox Client sends an Inbox Message to a TAXII Server and prints the ' \
12 | 'Status Message response to standard out. The Inbox Client has a "built in" STIX document ' \
13 | 'that is sent by default.'
14 | path = '/taxii-data'
15 |
16 | # http://stix.mitre.org/language/version1.1.1/#samples
17 | # http://stix.mitre.org/language/version1.1.1/stix_v1.0_samples_20130408.zip
18 | stix_watchlist = '''
19 |
36 |
55 |
56 | Example watchlist that contains domain information.
57 | Indicators - Watchlist
58 |
59 |
60 |
62 | Domain Watchlist
63 | Sample domain Indicator for this watchlist
64 |
65 |
66 |
67 | malicious1.example.com##comma##malicious2.example.com##comma##malicious3.example.com
69 |
70 |
71 |
72 |
73 |
74 | '''
75 |
76 | def get_arg_parser(self, *args, **kwargs):
77 | parser = super(InboxClient11Script, self).get_arg_parser(*args, **kwargs)
78 | parser.add_argument("--content-binding",
79 | dest="content_binding",
80 | default=CB_STIX_XML_111,
81 | help="Content binding of the Content Block to send. Defaults to %s" % CB_STIX_XML_111)
82 | parser.add_argument("--subtype",
83 | dest="subtype",
84 | default=None,
85 | help="The subtype of the Content Binding. Defaults to None")
86 | parser.add_argument("--content-file",
87 | dest="content_file",
88 | default=self.stix_watchlist,
89 | help="Content of the Content Block to send. Defaults to a STIX watchlist.")
90 | parser.add_argument("--dcn",
91 | dest="dcn",
92 | default=None,
93 | help="The Destination Collection Name for this Inbox Message. Defaults to None. "
94 | "This script only supports one Destination Collection Name")
95 | return parser
96 |
97 | def create_request_message(self, args):
98 | if args.content_file is self.stix_watchlist:
99 | data = self.stix_watchlist
100 | else:
101 | with open(args.content_file, 'r') as f:
102 | data = f.read()
103 |
104 | cb = tm11.ContentBlock(tm11.ContentBinding(args.content_binding), data)
105 | if args.subtype is not None:
106 | cb.content_binding.subtype_ids.append(args.subtype)
107 |
108 | inbox_message = tm11.InboxMessage(message_id=tm11.generate_message_id(), content_blocks=[cb])
109 | if args.dcn:
110 | inbox_message.destination_collection_names.append(args.dcn)
111 |
112 | return inbox_message
113 |
114 |
115 | def main():
116 | script = InboxClient11Script()
117 | script()
118 |
119 | if __name__ == "__main__":
120 | main()
121 |
--------------------------------------------------------------------------------
/libtaxii/scripts/inbox_client_10.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright (c) 2017, The MITRE Corporation
4 | # For license information, see the LICENSE.txt file
5 |
6 | from libtaxii.scripts import TaxiiScript
7 | import libtaxii.messages_10 as tm10
8 | from libtaxii.constants import *
9 | from libtaxii.common import generate_message_id
10 |
11 |
12 | class InboxClient10Script(TaxiiScript):
13 | taxii_version = VID_TAXII_XML_10
14 |
15 | parser_description = 'The TAXII 1.0 Inbox Client sends an Inbox Message to a TAXII Server and prints the ' \
16 | 'Status Message response to standard out. The Inbox Client has a "built in" STIX document ' \
17 | 'that is sent by default.'
18 | path = '/taxii-data'
19 |
20 | # http://stix.mitre.org/language/version1.1.1/#samples
21 | # http://stix.mitre.org/language/version1.1.1/stix_v1.0_samples_20130408.zip
22 | stix_watchlist = '''
23 |
40 |
59 |
60 | Example watchlist that contains domain information.
61 | Indicators - Watchlist
62 |
63 |
64 |
66 | Domain Watchlist
67 | Sample domain Indicator for this watchlist
68 |
69 |
70 |
71 | malicious1.example.com##comma##malicious2.example.com##comma##malicious3.example.com
73 |
74 |
75 |
76 |
77 |
78 | '''
79 |
80 | def get_arg_parser(self, *args, **kwargs):
81 | parser = super(InboxClient10Script, self).get_arg_parser(*args, **kwargs)
82 | parser.add_argument("--content-binding",
83 | dest="content_binding",
84 | default=CB_STIX_XML_111,
85 | help="Content binding of the Content Block to send. Defaults to %s" % CB_STIX_XML_111)
86 | parser.add_argument("--subtype",
87 | dest="subtype",
88 | default=None,
89 | help="The subtype of the Content Binding. Defaults to None")
90 | parser.add_argument("--content-file",
91 | dest="content_file",
92 | default=self.stix_watchlist,
93 | help="Content of the Content Block to send. Defaults to a STIX watchlist.")
94 | return parser
95 |
96 | def create_request_message(self, args):
97 | if args.content_file is self.stix_watchlist:
98 | data = self.stix_watchlist
99 | else:
100 | with open(args.content_file, 'r') as f:
101 | data = f.read()
102 |
103 | cb = tm10.ContentBlock(args.content_binding, data)
104 | if args.subtype is not None:
105 | cb.content_binding.subtype_ids.append(args.subtype)
106 |
107 | inbox_message = tm10.InboxMessage(message_id=generate_message_id(), content_blocks=[cb])
108 |
109 | return inbox_message
110 |
111 |
112 | def main():
113 | script = InboxClient10Script()
114 | script()
115 |
116 | if __name__ == "__main__":
117 | main()
118 |
--------------------------------------------------------------------------------
/libtaxii/scripts/poll_client.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright (c) 2017, The MITRE Corporation
4 | # For license information, see the LICENSE.txt file
5 |
6 | from libtaxii.scripts import TaxiiScript, add_poll_response_args
7 | import libtaxii.messages_11 as tm11
8 | import os
9 | import sys
10 | import dateutil.parser
11 | import datetime
12 | from libtaxii.common import gen_filename
13 | from libtaxii.constants import *
14 |
15 |
16 | class PollClient11Script(TaxiiScript):
17 | parser_description = ('The TAXII 1.1 Poll Client sends a Poll Request to a TAXII Poll Service then, depending on'
18 | ' the provided command line arguments, writes the Content Blocks in the response to disk.'
19 | ' Various options for the Poll Request can be set on the command line.')
20 | path = '/taxii-data'
21 |
22 | def get_arg_parser(self, *args, **kwargs):
23 | parser = super(PollClient11Script, self).get_arg_parser(*args, **kwargs)
24 | parser.add_argument("--collection",
25 | dest="collection",
26 | default="default",
27 | help="Data Collection to poll. Defaults to 'default'.")
28 | parser.add_argument("--begin-timestamp",
29 | dest="begin_ts",
30 | default=None,
31 | help="The begin timestamp (format: YYYY-MM-DDTHH:MM:SS.ssssss+/-hh:mm) "
32 | "for the poll request. Defaults to None.")
33 | parser.add_argument("--end-timestamp",
34 | dest="end_ts",
35 | default=None,
36 | help="The end timestamp (format: YYYY-MM-DDTHH:MM:SS.ssssss+/-hh:mm) "
37 | "for the poll request. Defaults to None.")
38 | parser.add_argument("--subscription-id",
39 | dest="subscription_id",
40 | default=None,
41 | help="The Subscription ID for the poll request. Defaults to None.")
42 | add_poll_response_args(parser)
43 | return parser
44 |
45 | def create_request_message(self, args):
46 | try:
47 | if args.begin_ts:
48 | begin_ts = dateutil.parser.parse(args.begin_ts)
49 | if not begin_ts.tzinfo:
50 | raise ValueError
51 | else:
52 | begin_ts = None
53 |
54 | if args.end_ts:
55 | end_ts = dateutil.parser.parse(args.end_ts)
56 | if not end_ts.tzinfo:
57 | raise ValueError
58 | else:
59 | end_ts = None
60 | except ValueError:
61 | print("Unable to parse timestamp value. Timestamp should include both date and time "
62 | "information along with a timezone or UTC offset (e.g., YYYY-MM-DDTHH:MM:SS.ssssss+/-hh:mm). "
63 | "Aborting poll.")
64 | sys.exit()
65 |
66 | create_kwargs = {'message_id': tm11.generate_message_id(),
67 | 'collection_name': args.collection,
68 | 'exclusive_begin_timestamp_label': begin_ts,
69 | 'inclusive_end_timestamp_label': end_ts}
70 |
71 | if args.subscription_id:
72 | create_kwargs['subscription_id'] = args.subscription_id
73 | else:
74 | create_kwargs['poll_parameters'] = tm11.PollRequest.PollParameters()
75 | poll_req = tm11.PollRequest(**create_kwargs)
76 | return poll_req
77 |
78 | def handle_response(self, response, args):
79 | super(PollClient11Script, self).handle_response(response, args)
80 |
81 | if response.message_type == MSG_POLL_RESPONSE:
82 | if response.more:
83 | print("This response has More=True, to request additional parts, use the following command:")
84 | print(" fulfillment_client --collection %s --result-id %s --result-part-number %s\r\n" %
85 | (response.collection_name, response.result_id, response.result_part_number + 1))
86 |
87 | self.write_cbs_from_poll_response_11(response, dest_dir=args.dest_dir, write_type_=args.write_type)
88 |
89 |
90 | def main():
91 | script = PollClient11Script()
92 | script()
93 |
94 |
95 | if __name__ == "__main__":
96 | main()
97 |
--------------------------------------------------------------------------------
/libtaxii/scripts/poll_client_10.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright (c) 2017, The MITRE Corporation
4 | # For license information, see the LICENSE.txt file
5 |
6 | from libtaxii.scripts import TaxiiScript, add_poll_response_args
7 | import libtaxii.messages_10 as tm10
8 | import dateutil.parser
9 | import datetime
10 | import sys
11 | import os
12 | from libtaxii.common import gen_filename
13 | from libtaxii.constants import *
14 |
15 |
16 | class PollClient10Script(TaxiiScript):
17 | taxii_version = VID_TAXII_XML_10
18 | parser_description = ('The TAXII 1.0 Poll Client sends a Poll Request message to a TAXII Server and then'
19 | 'prints the Poll Response message to standard out, saving the Content Blocks to disk ('
20 | 'depending on the command line arguments).')
21 | path = '/taxii-data'
22 |
23 | def get_arg_parser(self, *args, **kwargs):
24 | parser = super(PollClient10Script, self).get_arg_parser(*args, **kwargs)
25 | parser.add_argument("--feed",
26 | dest="feed",
27 | default="default",
28 | help="Data Collection to poll. Defaults to 'default'.")
29 | parser.add_argument("--begin-timestamp",
30 | dest="begin_ts",
31 | default=None,
32 | help="The begin timestamp (format: YYYY-MM-DDTHH:MM:SS.ssssss+/-hh:mm) for the poll "
33 | "request. Defaults to None.")
34 | parser.add_argument("--end-timestamp",
35 | dest="end_ts",
36 | default=None,
37 | help="The end timestamp (format: YYYY-MM-DDTHH:MM:SS.ssssss+/-hh:mm) for the poll request. "
38 | "Defaults to None.")
39 | parser.add_argument("--subscription-id",
40 | dest="subs_id",
41 | default=None,
42 | help="The subscription ID to use. Defaults to None")
43 | add_poll_response_args(parser)
44 | return parser
45 |
46 | def create_request_message(self, args):
47 | try:
48 | if args.begin_ts:
49 | begin_ts = dateutil.parser.parse(args.begin_ts)
50 | if not begin_ts.tzinfo:
51 | raise ValueError
52 | else:
53 | begin_ts = None
54 |
55 | if args.end_ts:
56 | end_ts = dateutil.parser.parse(args.end_ts)
57 | if not end_ts.tzinfo:
58 | raise ValueError
59 | else:
60 | end_ts = None
61 | except ValueError:
62 | print("Unable to parse timestamp value. Timestamp should include both date and time information along "
63 | "with a timezone or UTC offset (e.g., YYYY-MM-DDTHH:MM:SS.ssssss+/-hh:mm). Aborting poll.")
64 | sys.exit()
65 |
66 | poll_req = tm10.PollRequest(message_id=tm10.generate_message_id(),
67 | feed_name=args.feed,
68 | exclusive_begin_timestamp_label=begin_ts,
69 | inclusive_end_timestamp_label=end_ts,
70 | subscription_id=args.subs_id)
71 | return poll_req
72 |
73 | def handle_response(self, response, args):
74 | super(PollClient10Script, self).handle_response(response, args)
75 | if response.message_type == tm10.MSG_POLL_RESPONSE:
76 | self.write_cbs_from_poll_response_10(response, dest_dir=args.dest_dir, write_type_=args.write_type)
77 |
78 |
79 | def main():
80 | script = PollClient10Script()
81 | script()
82 |
83 |
84 | if __name__ == "__main__":
85 | main()
86 |
--------------------------------------------------------------------------------
/libtaxii/scripts/query_client.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright (c) 2017, The MITRE Corporation
4 | # For license information, see the LICENSE.txt file
5 |
6 | import libtaxii.taxii_default_query as tdq
7 | from libtaxii.constants import *
8 | from .poll_client import PollClient11Script
9 |
10 |
11 | class QueryClient11Script(PollClient11Script):
12 | parser_description = "The TAXII 1.1 Query Client sends a Poll Request message to a TAXII Server (queries are " \
13 | "contained in Poll Request messages) and prints out the resulting Poll Response message" \
14 | "to standard out. The Content Blocks are saved to disk (depending on the command line" \
15 | "options)."
16 | path = '/taxii-data'
17 |
18 | def get_arg_parser(self, *args, **kwargs):
19 | parser = super(QueryClient11Script, self).get_arg_parser(*args, **kwargs)
20 | parser.add_argument("--tev",
21 | dest="tev",
22 | default=CB_STIX_XML_111,
23 | help="Indicate which Targeting Expression Vocabulary is being used. Defaults to "
24 | "STIX XML 1.1.1")
25 | parser.add_argument("--target",
26 | dest="target",
27 | default="**/@id",
28 | help="The targeting expression to use. Defaults to **/@id (Any id, anywhere).")
29 | parser.add_argument("--rel",
30 | dest="relationship",
31 | default="equals",
32 | help="The relationship to use (e.g., equals). Defaults to equals.")
33 | parser.add_argument("--cm",
34 | dest="capability_module",
35 | default=CM_CORE,
36 | help="The capability module to use. Defaults to CORE.")
37 | # Parameters - optional depending on what relationship is chosen
38 | parser.add_argument("--value",
39 | dest=tdq.P_VALUE,
40 | default=None,
41 | help="The value to look for. Required (or not) and allowed values depend "
42 | "on the relationship.")
43 | parser.add_argument("--match-type",
44 | dest=tdq.P_MATCH_TYPE,
45 | default='case_insensitive_string',
46 | choices=['case_sensitive_string', 'case_insensitive_string', 'number'],
47 | help="The match type. Required (or not) and allowed values depend on the relationship. "
48 | "Defaults to \'case_insensitive_string\'")
49 | parser.add_argument("--case-sensitive",
50 | dest=tdq.P_CASE_SENSITIVE,
51 | default=None,
52 | choices=[True, False],
53 | help="Whether the match is case sensitive. Required (or not) and allowed values "
54 | "depend on the relationship. Defaults to \'None\'")
55 | return parser
56 |
57 | def create_request_message(self, args):
58 | msg = super(QueryClient11Script, self).create_request_message(args)
59 | if args.subscription_id is not None:
60 | return msg # Query goes in Poll Parameters, which can't be specified with a subscription
61 |
62 | capability_module = tdq.capability_modules.get(args.capability_module, None)
63 | if capability_module is None:
64 | raise ValueError("Unknown Capability Module specified: %s" % args.capability_module)
65 |
66 | relationship = capability_module.relationships.get(args.relationship, None)
67 | if relationship is None:
68 | raise ValueError("Unknown Relationship: %s" % args.relationship)
69 |
70 | params = {}
71 |
72 | for parameter in tdq.P_NAMES:
73 | param_obj = relationship.parameters.get(parameter, None) # Will either be a parameter object or None
74 | param_value = getattr(args, parameter) # Will either be a value or None
75 |
76 | if param_obj and not param_value:
77 | raise ValueError('The parameter "%s" is needed and was not specified. Specify using --%s ' %
78 | (parameter, parameter.replace('_', '-')))
79 | if param_value and not param_obj:
80 | raise ValueError('The parameter %s was specified and is not needed' % parameter)
81 |
82 | if param_obj:
83 | param_obj.verify(param_value)
84 | params[parameter] = param_value
85 |
86 | test = tdq.Test(capability_id=capability_module.capability_module_id,
87 | relationship=relationship.name,
88 | parameters=params)
89 |
90 | criterion = tdq.Criterion(target=args.target, test=test)
91 | criteria = tdq.Criteria(operator=OP_AND, criterion=[criterion])
92 | q = tdq.DefaultQuery(args.tev, criteria)
93 | msg.poll_parameters.query = q
94 |
95 | return msg
96 |
97 |
98 |
99 | def main():
100 | script = QueryClient11Script()
101 | script()
102 |
103 | if __name__ == "__main__":
104 | main()
105 |
--------------------------------------------------------------------------------
/libtaxii/test/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TAXIIProject/libtaxii/41f413357f4aaaaf99e37152558bb7464dbf5768/libtaxii/test/__init__.py
--------------------------------------------------------------------------------
/libtaxii/test/argument_parser_test.py:
--------------------------------------------------------------------------------
1 | import os
2 | import unittest
3 |
4 | import libtaxii.scripts.poll_client as pc11
5 |
6 |
7 | class ArgumentParserTests(unittest.TestCase):
8 |
9 | def setUp(self):
10 | self.module_path = os.path.dirname(__file__)
11 |
12 | def test_valid_argument_passing_poll_client11(self):
13 | script = pc11.PollClient11Script()
14 | arg_parse = script.get_arg_parser(script.parser_description, path=script.path)
15 | namespace = arg_parse.parse_args(
16 | [
17 | "--from-file", os.path.join(self.module_path, "data", "configuration.ini")
18 | ]
19 | )
20 | self.assertEqual(namespace.url, "http://hailataxii2.com:80")
21 | self.assertEqual(namespace.path, "/taxii-data")
22 | self.assertEqual(namespace.port, 80)
23 | self.assertEqual(namespace.password, "myS3crEtp@asswOrd!")
24 |
25 | def test_argument_override_poll_client11(self):
26 | script = pc11.PollClient11Script()
27 | arg_parse = script.get_arg_parser(script.parser_description, path=script.path)
28 | namespace = arg_parse.parse_args(
29 | [
30 | "-u", "http://hailataxii.com:80",
31 | "--from-file", os.path.join(self.module_path, "data", "configuration.ini")
32 | ]
33 | )
34 | self.assertEqual(namespace.url, "http://hailataxii2.com:80") # note the argument was overwritten
35 | self.assertEqual(namespace.path, "/taxii-data")
36 | self.assertEqual(namespace.port, 80)
37 | self.assertEqual(namespace.password, "myS3crEtp@asswOrd!")
38 |
--------------------------------------------------------------------------------
/libtaxii/test/clients_test.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2017, The MITRE Corporation
2 | # For license information, see the LICENSE.txt file
3 |
4 | import datetime
5 |
6 | from dateutil.tz import tzutc
7 |
8 | import libtaxii as t
9 | import libtaxii.clients as tc
10 | import libtaxii.messages as tm
11 | from libtaxii.constants import *
12 |
13 | # NOTE: This cannot currently be run as a unit test because it needs a server
14 | # to connect to.
15 | def client_example():
16 |
17 | # Create the TAXII HTTPS Client
18 | client = tc.HttpClient()
19 |
20 | # Uncomment to use HTTPS
21 | client.set_use_https(True)
22 |
23 | # Uncomment to use basic authentication
24 | # client.set_auth_type(tc.HttpClient.AUTH_BASIC)
25 | # client.set_auth_credentials({'username':'some_username', 'password':'some_password'})
26 |
27 | # Uncomment to use certificate-based authentication
28 | client.set_auth_type(tc.HttpClient.AUTH_CERT)
29 | client.set_auth_credentials({'key_file': 'keyfile',
30 | 'cert_file': 'certfile'})
31 |
32 | # Uncomment to set a proxy
33 | # client.set_proxy(tc.HttpClient.PROXY_HTTP, 'http://proxy.company.com:80')
34 |
35 | # Create the poll request
36 | poll_request1 = tm.PollRequest(message_id=tm.generate_message_id(), feed_name='TheFeedToPoll')
37 |
38 | # Call without a proxy
39 | http_response = client.call_taxii_service2('hostname', '/poll_service_path/', VID_TAXII_XML_10, poll_request1.to_xml())
40 |
41 | print(http_response.__class__.__name__)
42 |
43 | taxii_message = t.get_message_from_http_response(http_response,
44 | poll_request1.message_id)
45 | print((taxii_message.to_xml()))
46 |
47 | if __name__ == "__main__":
48 | client_example()
49 |
--------------------------------------------------------------------------------
/libtaxii/test/data/configuration.ini:
--------------------------------------------------------------------------------
1 | [libtaxii]
2 | url = http://hailataxii2.com:80
3 | pass = myS3crEtp@asswOrd!
4 |
--------------------------------------------------------------------------------
/libtaxii/test/input/1.1/Collection_Information_Response.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Warrgghghglble.
5 |
6 |
7 | So improve information. Much amaze.
8 |
9 |
10 |
11 |
12 |
13 |
14 | urn:taxii.mitre.org:protocol:http:1.0
15 | https://example.com/inbox/
16 | urn:taxii.mitre.org:message:xml:1.1
17 |
18 |
19 | urn:taxii.mitre.org:protocol:http:1.0
20 | https://example.com/inbox/
21 | urn:taxii.mitre.org:message:xml:1.1
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/libtaxii/test/input/1.1/Discovery_Response.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | urn:taxii.mitre.org:protocol:http:1.0
6 | http://taxiitest.mitre.org/services/inbox/default
7 | urn:taxii.mitre.org:message:xml:1.1
8 |
9 |
10 |
11 | urn:taxii.mitre.org:protocol:http:1.0
12 | http://taxiitest.mitre.org/services/poll
13 | urn:taxii.mitre.org:message:xml:1.1
14 |
15 |
16 | urn:taxii.mitre.org:protocol:http:1.0
17 | http://taxiitest.mitre.org/services/discovery
18 | urn:taxii.mitre.org:message:xml:1.1
19 |
20 |
21 |
--------------------------------------------------------------------------------
/libtaxii/test/input/1.1/Inbox_Message.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | collection1
4 | collection2
5 | Hello!
6 |
7 | SubsId021
8 | 2014-10-21T15:21:50.895-04:00
9 | 2014-10-21T15:21:50.895-04:00
10 |
11 | 22
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | 2014-10-21T19:21:50.805Z
20 | Hullo!
21 | The quick brown fox jumped over the lazy dogs.
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/libtaxii/test/input/1.1/Subscription_Management_Request.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | FULL
5 |
6 |
7 |
8 |
9 | **
10 |
11 | Test value
12 | case_sensitive_string
13 |
14 |
15 |
16 | **/Description
17 |
18 | Tue Oct 21 15:34:33 EDT 2014
19 |
20 |
21 |
22 |
23 | **
24 |
25 | Test value
26 | case_sensitive_string
27 |
28 |
29 |
30 | STIX_Package/Indicators/Indicator/@id
31 |
32 | [A-Z]*
33 | true
34 |
35 |
36 |
37 | **/Description
38 |
39 | Tue Oct 21 15:34:33 EDT 2014
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/libtaxii/test/input/1.1/Subscription_Management_Response.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hullo!
4 |
5 | Subs001
6 |
7 | COUNT_ONLY
8 |
9 |
10 |
11 |
12 |
13 | **
14 |
15 | Test value
16 | case_sensitive_string
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | urn:taxii.mitre.org:protocol:https:1.0
25 | https://example.com/inboxAddress/
26 | urn:taxii.mitre.org:message:xml:1.1
27 |
28 |
29 | urn:taxii.mitre.org:protocol:https:1.0
30 | https://example.com/poll1/
31 | urn:taxii.mitre.org:message:xml:1.1
32 |
33 |
34 | urn:taxii.mitre.org:protocol:https:1.0
35 | https://example.com/poll2/
36 | urn:taxii.mitre.org:message:xml:1.1
37 |
38 |
39 | urn:taxii.mitre.org:protocol:https:1.0
40 | https://example.com/poll3/
41 | urn:taxii.mitre.org:message:xml:1.1
42 |
43 |
44 |
45 | Subs001
46 |
47 | COUNT_ONLY
48 |
49 |
50 |
51 |
52 |
53 | **
54 |
55 | Test value
56 | case_sensitive_string
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | urn:taxii.mitre.org:protocol:https:1.0
65 | https://example.com/inboxAddress/
66 | urn:taxii.mitre.org:message:xml:1.1
67 |
68 |
69 |
70 | Subs001
71 |
72 |
73 |
--------------------------------------------------------------------------------
/libtaxii/test/output/1.1/readme.md:
--------------------------------------------------------------------------------
1 | Placeholder for Test output files.
--------------------------------------------------------------------------------
/libtaxii/test/test_clients.py:
--------------------------------------------------------------------------------
1 | from __future__ import unicode_literals
2 |
3 | from lxml import etree
4 |
5 | from libtaxii.clients import VerifiableHTTPSConnection
6 |
7 |
8 | def test_connection():
9 | # This is a basic test just to confirm that we pass the right arguments
10 | # in the right order to a (non-TAXII) HTTPS server
11 |
12 | conn = VerifiableHTTPSConnection("https://httpbin.org/", 443)
13 |
--------------------------------------------------------------------------------
/libtaxii/test/test_xml_encoding.py:
--------------------------------------------------------------------------------
1 | from __future__ import unicode_literals
2 |
3 | from lxml import etree
4 |
5 | from libtaxii.common import parse_xml_string
6 | from libtaxii.constants import CB_STIX_XML_111
7 | from libtaxii.messages_10 import ContentBlock as ContentBlock10
8 | from libtaxii.messages_11 import get_message_from_xml, ContentBlock as ContentBlock11
9 |
10 |
11 | discovery_request_with_encoding_bytes = b"""
12 |
16 | """
17 |
18 | discovery_request_with_encoding_unicode = """
19 |
23 | """
24 |
25 | stix_package_bytes = b"""
26 |
29 |
30 | Test Package
31 |
32 |
33 | """
34 |
35 | stix_package_unicode = """
36 |
39 |
40 | Test Package
41 |
42 |
43 | """
44 |
45 |
46 | def test_parsing_byte_string_with_encoding():
47 | x = parse_xml_string(b"""""")
48 | assert x.tag == "foo"
49 |
50 |
51 | def test_parsing_byte_string_without_encoding():
52 | x = parse_xml_string(b"""""")
53 | assert x.tag == "bar"
54 |
55 |
56 | def test_parsing_unicode_string_with_encoding():
57 | x = parse_xml_string("""""")
58 | assert x.tag == "baz"
59 |
60 |
61 | def test_parsing_unicode_string_without_encoding():
62 | x = parse_xml_string("""""")
63 | assert x.tag == "quz"
64 |
65 |
66 | def test_get_xml_from_byte_string():
67 | req = get_message_from_xml(discovery_request_with_encoding_bytes)
68 |
69 | assert req is not None
70 | assert req.message_id == "331bf15a-76a0-4e29-8444-6e986e514e29"
71 |
72 |
73 | def test_get_xml_from_unicode_string():
74 | req = get_message_from_xml(discovery_request_with_encoding_unicode)
75 |
76 | assert req is not None
77 | assert req.message_id == "331bf15a-76a0-4e29-8444-6e986e514e29"
78 |
79 |
80 | def test_content_block_11_bytes():
81 | content_block = ContentBlock11(CB_STIX_XML_111, stix_package_bytes)
82 |
83 | assert content_block.content_is_xml is True
84 | assert b"Indicator-ba1d406e-937c-414f-9231-6e1dbe64fe8b" in content_block.content
85 |
86 |
87 | def test_content_block_11_unicode():
88 | content_block = ContentBlock11(CB_STIX_XML_111, stix_package_unicode)
89 |
90 | assert content_block.content_is_xml is True
91 | # Content is always in bytes
92 | assert b"Indicator-ba1d406e-937c-414f-9231-6e1dbe64fe8b" in content_block.content
93 |
94 |
95 | def test_content_block_10_bytes():
96 | content_block = ContentBlock10(CB_STIX_XML_111, stix_package_bytes)
97 |
98 | assert content_block.content_is_xml is True
99 | assert isinstance(content_block._content, etree._Element)
100 | assert b"Indicator-ba1d406e-937c-414f-9231-6e1dbe64fe8b" in content_block.content
101 |
102 |
103 | def test_content_block_10_unicode():
104 | content_block = ContentBlock10(CB_STIX_XML_111, stix_package_unicode)
105 |
106 | assert content_block.content_is_xml is True
107 | # Content is always in bytes
108 | assert isinstance(content_block._content, etree._Element)
109 | assert b"Indicator-ba1d406e-937c-414f-9231-6e1dbe64fe8b" in content_block.content
110 |
--------------------------------------------------------------------------------
/libtaxii/test/to_text_11_test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright (c) 2017, The MITRE Corporation
4 | # For license information, see the LICENSE.txt file
5 |
6 | import glob
7 | import os
8 | import libtaxii.messages_11 as tm11
9 |
10 |
11 | input_path = os.path.join('input', '1.1')
12 | output_path = os.path.join('output', '1.1')
13 |
14 |
15 | def main():
16 | input_fns = glob.glob(os.path.join(input_path, '*.xml'))
17 |
18 | for input_fn in input_fns:
19 | with open(input_fn, 'r') as f:
20 | text = f.read()
21 |
22 | # parse the file to a TAXII message/object
23 | msg = tm11.get_message_from_xml(text)
24 |
25 | # create the output files
26 | basename = os.path.splitext(os.path.basename(input_fn))[0]
27 |
28 | # write XML and text to files.
29 | xml_out = os.path.join(output_path, basename + ".xml")
30 | with open(xml_out, 'w') as f:
31 | f.write(msg.to_xml(pretty_print=True))
32 |
33 | txt_out = os.path.join(output_path, basename + ".txt")
34 | with open(txt_out, 'w') as f:
35 | f.write(msg.to_text())
36 |
37 |
38 | if __name__ == '__main__':
39 | main()
40 |
--------------------------------------------------------------------------------
/libtaxii/test/validation_test.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2017, The MITRE Corporation
2 | # For license information, see the LICENSE.txt file
3 |
4 | import unittest
5 |
6 | from libtaxii.validation import do_check, message_id_regex_10
7 |
8 |
9 | class ValidationTests(unittest.TestCase):
10 |
11 | def test_numeric_regex_valid(self):
12 | # This message ID is valid. It should not raise an exception
13 | do_check("12345", "Test Value", regex_tuple=message_id_regex_10)
14 |
15 | # See: https://github.com/TAXIIProject/libtaxii/issues/166
16 | def test_numeric_regex_invalid_end(self):
17 | # This message ID is not valid.
18 | args = ("12345abcd", "Message ID")
19 | kwargs = {'regex_tuple': message_id_regex_10}
20 | self.assertRaises(ValueError, do_check, *args, **kwargs)
21 |
22 |
23 | if __name__ == '__main__':
24 | unittest.main()
25 |
--------------------------------------------------------------------------------
/libtaxii/validation.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2017, The MITRE Corporation
2 | # For license information, see the LICENSE.txt file
3 |
4 | """
5 | Common data validation functions used across libtaxii
6 | """
7 |
8 |
9 | import collections
10 | import re
11 | import datetime
12 | from lxml import etree
13 | import os
14 |
15 | from .common import (parse, parse_datetime_string)
16 | import six
17 |
18 | # General purpose helper methods #
19 |
20 | RegexTuple = collections.namedtuple('_RegexTuple', ['regex', 'title'])
21 | # URI regex per http://tools.ietf.org/html/rfc3986
22 | uri_regex = RegexTuple("(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?", "URI Format")
23 | message_id_regex_10 = RegexTuple("^[0-9]+$", "Numbers only")
24 | targeting_expression_regex = RegexTuple("^(@?\w+|\*{1,2})(/(@?\w+|\*{1,2}))*$", "Targeting Expression Syntax")
25 |
26 | _none_error = "%s is not allowed to be None and the provided value was None"
27 | _type_error = "%s must be of type %s. The incorrect value was of type %s"
28 | _regex_error = "%s must be a string conforming to %s. The incorrect value was: %s"
29 | _tuple_error = "%s must be one of %s. The incorrect value was %s"
30 |
31 |
32 | def do_check(var, varname, type=None, regex_tuple=None, value_tuple=None, can_be_none=False):
33 | """
34 | Checks supplied var against all of the supplied checks using the following
35 | process:
36 |
37 | 1. If var is iterable, call this function for every item in the iterable object
38 | 2. If the var is none and can be none, return
39 | 3. If the var is none and cannot be none, raise ValueError
40 | 4. If a type is specified, and the var is not of the specified type, raise ValueError
41 | 5. If a regex is specified, and the var doesn't match the regex, raise ValueError
42 | 6. If a value_tuple is specified, and the var is not in the value_tuple, raise ValueError
43 |
44 | varname is used in the error messages
45 |
46 | """
47 |
48 | if isinstance(var, list) or isinstance(var, set) or isinstance(var, tuple):
49 |
50 | x = 0
51 | for item in var:
52 | do_check(item, "%s[%s]" % (varname, x), type, regex_tuple, value_tuple, can_be_none)
53 | x = x + 1
54 |
55 | return
56 |
57 | if var is None and can_be_none:
58 | return
59 |
60 | if var is None and not can_be_none:
61 | raise ValueError(_none_error % varname)
62 |
63 | if type is not None:
64 | if not isinstance(var, type):
65 | bad_type = var.__class__.__name__
66 | raise ValueError(_type_error % (varname, type, bad_type))
67 |
68 | if regex_tuple is not None:
69 | if not isinstance(var, six.string_types):
70 | raise ValueError('%s was about to undergo a regex check, but is not of type basestring! Regex check was not performed' % (varname))
71 | if re.match(regex_tuple.regex, var) is None:
72 | raise ValueError(_regex_error % (varname, regex_tuple.title, var))
73 |
74 | if value_tuple is not None:
75 | if var not in value_tuple:
76 | raise ValueError(_tuple_error % (varname, value_tuple, var))
77 | return
78 |
79 |
80 | def check_timestamp_label(timestamp_label, varname, can_be_none=False):
81 | """
82 | Checks the timestamp_label to see if it is a valid timestamp label
83 | using the following process:
84 |
85 | 1. If the timestamp_label is None and is allowed to be None, Pass
86 | 2. If the timestamp_label is None and is not allowed to be None, Fail
87 | 3. If the timestamp_label arg is a string, convert to datetime
88 | 4. If the timestamp_label does not have a tzinfo attribute, Fail
89 | 5. Pass
90 | """
91 |
92 | if timestamp_label is None and can_be_none:
93 | return
94 |
95 | if timestamp_label is None and not can_be_none:
96 | raise ValueError(_none_error % varname)
97 |
98 | if isinstance(timestamp_label, six.string_types):
99 | timestamp_label = parse_datetime_string(timestamp_label)
100 |
101 | do_check(timestamp_label, varname, type=datetime.datetime, can_be_none=can_be_none)
102 |
103 | if timestamp_label.tzinfo is None:
104 | raise ValueError('%s.tzinfo must not be None!' % varname)
105 |
106 | return timestamp_label
107 |
108 |
109 | class SchemaValidationResult(object):
110 | """A wrapper for the results of schema validation."""
111 |
112 | def __init__(self, valid, error_log):
113 | self.valid = valid
114 | self.error_log = error_log
115 |
116 | _pkg_dir = os.path.dirname(__file__)
117 |
118 | #: Automatically-calculated path to the bundled TAXII 1.0 schema.
119 | TAXII_10_SCHEMA = os.path.join(_pkg_dir, "xsd", "TAXII_XMLMessageBinding_Schema.xsd")
120 |
121 | #: Automatically-calculated path to the bundled TAXII 1.1 schema.
122 | TAXII_11_SCHEMA = os.path.join(_pkg_dir, "xsd", "TAXII_XMLMessageBinding_Schema_11.xsd")
123 |
124 |
125 | class SchemaValidator(object):
126 | """
127 | A helper class for TAXII Schema Validation.
128 |
129 | Example:
130 | See validate_etree(...) for an example how to use this class
131 | """
132 |
133 | # Create class-level variables equal to module-level variables for
134 | # backwards-compatibility
135 | TAXII_10_SCHEMA = TAXII_10_SCHEMA
136 | TAXII_11_SCHEMA = TAXII_11_SCHEMA
137 |
138 | def __init__(self, schema_file):
139 | """
140 | Args:
141 | schema_file (str) - The file location of the schema to
142 | validate against. Use the TAXII_11_SCHEMA
143 | and TAXII_10_SCHEMA constants to validate
144 | against TAXII 1.1 / 1.0. This schema file
145 | will be used when validate_file/string/etree
146 | is used.
147 | """
148 | schema_doc = parse(schema_file, allow_file=True)
149 | self.xml_schema = etree.XMLSchema(schema_doc)
150 |
151 | def validate_file(self, file_location):
152 | """
153 | A wrapper for validate_etree. Parses file_location,
154 | turns it into an etree, then calls validate_etree( ... )
155 | """
156 |
157 | with open(file_location, 'r') as f:
158 | etree_xml = parse(f, allow_file=True)
159 |
160 | return self.validate_etree(etree_xml)
161 |
162 | def validate_string(self, xml_string):
163 | """
164 | A wrapper for validate_etree. Parses xml_string,
165 | turns it into an etree, then calls validate_etree( ... )
166 | """
167 | etree_xml = parse(xml_string, allow_file=False)
168 | return self.validate_etree(etree_xml)
169 |
170 | def validate_etree(self, etree_xml):
171 | """Validate an LXML etree with the specified schema_file.
172 |
173 | Args:
174 | etree_xml (etree): The XML to validate.
175 | schema_file (str): The schema file to validate against
176 |
177 | Returns:
178 | A SchemaValidationResult object
179 |
180 | Raises:
181 | lxml.etree.XMLSyntaxError: When the XML to be validated is not well formed
182 |
183 | Example:
184 | .. code-block:: python
185 |
186 | from libtaxii import messages_11
187 | from libtaxii.validation import SchemaValidator, TAXII_11_SCHEMA
188 | from lxml.etree import XMLSyntaxError
189 |
190 | sv = SchemaValidator(TAXII_11_SCHEMA)
191 |
192 | try:
193 | result = sv.validate_etree(some_etree)
194 | # Note that validate_string() and validate_file() can also be used
195 | except XMLSyntaxError:
196 | # Handle this exception, which occurs when
197 | # some_xml_string is not valid XML (e.g., 'foo')
198 |
199 | if not result.valid:
200 | for error in result.error_log:
201 | print error
202 | sys.exit(1)
203 |
204 | # At this point, the XML is schema valid
205 | do_something(some_xml_string)
206 | """
207 | valid = self.xml_schema.validate(etree_xml)
208 | return SchemaValidationResult(valid, self.xml_schema.error_log)
209 |
210 |
211 | class TAXII10Validator(SchemaValidator):
212 | """A :py:class:`SchemaValidator` that uses the TAXII 1.0 Schemas"""
213 |
214 | def __init__(self):
215 | super(TAXII10Validator, self).__init__(TAXII_10_SCHEMA)
216 |
217 |
218 | class TAXII11Validator(SchemaValidator):
219 | """A :py:class:`SchemaValidator` that uses the TAXII 1.1 Schemas"""
220 |
221 | def __init__(self):
222 | super(TAXII11Validator, self).__init__(TAXII_11_SCHEMA)
223 |
--------------------------------------------------------------------------------
/libtaxii/version.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2017, The MITRE Corporation
2 | # For license information, see the LICENSE.txt file
3 |
4 | __version__ = "1.1.119"
5 |
--------------------------------------------------------------------------------
/libtaxii/xsd/TAXII_DefaultQuery_Schema.xsd:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 | An XML element. Its body consists only of the indicated XML fields.
11 |
12 |
13 |
14 |
15 |
16 | An XML AnyURI indicating the Targeting Expression Vocabulary that will be used in this query’s Target field(s).
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | The element name indicates that this is a Targeting Expression Information field. Its body consists only of the indicated XML Fields.
25 |
26 |
27 |
28 |
29 | An XML AnyURI indicating a Capability Module.
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | An XML element. This element MUST consist only of the indicated XML fields. The subfields of this Criteria are the same as the parent Criteria (e.g., this is a recursive field), though they are not listed here.
39 |
40 |
41 |
42 |
43 | An XML element. This element MUST consist only of the indicated XML fields.
44 |
45 |
46 |
47 |
48 |
49 | An XML string containing an operator. Must be one of "AND" or "OR".
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | An XML string containing a Targeting Expression identifying the region of the record that is being targeted.
64 |
65 |
66 |
67 |
68 | An XML element containing the Test. This element MUST consist only of the indicated XML fields.
69 |
70 |
71 |
72 |
73 |
74 | An XML boolean indicating whether the result of the Criterion should be negated. The default value for this field is ‘false’.
75 |
76 |
77 |
78 |
79 |
80 |
82 |
83 | An XML string containing the value of this parameter.
84 |
85 |
86 |
87 |
88 |
89 | An XML AnyURI indicating the Capability Module used in this Test.
90 |
91 |
92 |
93 |
94 | An XML string containing the relationship.
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 | An XML string containing the name of this parameter.
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 | An XML String containing a Targeting Expression. At least one of Preferred_Scope or Allowed_Scope MUST be present (though this is not schema enforced).
114 |
115 |
116 |
117 |
118 | An XML String containing a Targeting Expression. At least one of Preferred_Scope or Allowed_Scope MUST be present (though this is not schema enforced).
119 |
120 |
121 |
122 |
123 |
124 | An XML AnyURI containing a Targeting Expression Vocabulary ID.
125 |
126 |
127 |
128 |
129 |
130 | The element name indicates that this is a TAXII Default Query. Its body MUST consist of only the indicated XML Fields.
131 |
132 |
133 |
134 |
135 | The element name indicates that this is a query information structure. Its body consists only of the indicated fields.
136 |
137 |
138 |
139 |
--------------------------------------------------------------------------------
/libtaxii/xsd/xmldsig-core-schema.xsd:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 | ]>
11 |
12 |
27 |
28 |
29 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
216 |
217 |
218 |
219 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Sphinx==1.6.1
2 | sphinx_rtd_theme==0.2.4
3 | pytest==3.0.7
4 | tox==2.7.0
5 | bumpversion==0.5.3
6 |
7 | -e .
8 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [bumpversion]
2 | current_version = 1.1.119
3 | tag_name = {new_version}
4 | commit = True
5 | tag = True
6 |
7 | [bumpversion:file:libtaxii/version.py]
8 |
9 | [metadata]
10 | license_file = LICENSE.txt
11 |
12 | [bdist_wheel]
13 | universal = True
14 |
15 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright (c) 2017, The MITRE Corporation
4 | # For license information, see the LICENSE.txt file
5 |
6 | from io import open
7 | from os.path import abspath, dirname, join
8 | import sys
9 |
10 | from setuptools import setup, find_packages
11 |
12 | BASE_DIR = dirname(abspath(__file__))
13 | VERSION_FILE = join(BASE_DIR, 'libtaxii', 'version.py')
14 |
15 |
16 | def get_version():
17 | with open(VERSION_FILE) as f:
18 | for line in f.readlines():
19 | if line.startswith("__version__"):
20 | version = line.split()[-1].strip('"')
21 | return version
22 | raise AttributeError("Package does not have a __version__")
23 |
24 |
25 | def get_long_description():
26 | with open('README.rst', encoding='utf-8') as f:
27 | return f.read()
28 |
29 |
30 | py_maj, py_minor = sys.version_info[:2]
31 | if (py_maj, py_minor) < (2, 6) or (py_maj == 3 and py_minor < 3):
32 | raise Exception('libtaxii requires Python 2.6, 2.7 or 3.3+')
33 |
34 |
35 | install_requires = [
36 | 'python-dateutil>=1.4.1',
37 | 'six>=1.9.0',
38 | ]
39 |
40 | # lxml has dropped support for Python 2.6, 3.3 after version 4.2.6
41 | if (py_maj, py_minor) == (2, 6) or (py_maj, py_minor) == (3, 3):
42 | install_requires.append('lxml>=2.2.3,<4.3.0')
43 | # lxml has dropped support for Python 2.6, 3.3, 3.4 after version 4.4.0
44 | elif (py_maj, py_minor) == (2, 6) or (py_maj, py_minor) == (3, 4):
45 | install_requires.append('lxml>=2.2.3,<4.4.0')
46 | else:
47 | install_requires.append('lxml>=2.2.3')
48 |
49 | if (py_maj, py_minor) < (2, 7):
50 | install_requires.append('argparse')
51 |
52 | setup(
53 | name='libtaxii',
54 | description='TAXII 1.X Library.',
55 | author='The MITRE Corporation',
56 | author_email='taxii@mitre.org',
57 | url='https://taxiiproject.github.io/',
58 | version=get_version(),
59 | packages=find_packages(),
60 | license='BSD',
61 | install_requires=install_requires,
62 | scripts=[
63 | 'libtaxii/scripts/collection_information_client.py',
64 | 'libtaxii/scripts/discovery_client.py',
65 | 'libtaxii/scripts/fulfillment_client.py',
66 | 'libtaxii/scripts/inbox_client.py',
67 | 'libtaxii/scripts/inbox_client_10.py',
68 | 'libtaxii/scripts/poll_client.py',
69 | 'libtaxii/scripts/query_client.py',
70 | 'libtaxii/scripts/discovery_client_10.py',
71 | 'libtaxii/scripts/feed_information_client_10.py',
72 | 'libtaxii/scripts/poll_client_10.py',
73 | ],
74 | entry_points={
75 | 'console_scripts': [
76 | 'collection_information_client = libtaxii.scripts.collection_information_client:main',
77 | 'discovery_client = libtaxii.scripts.discovery_client:main',
78 | 'fulfillment_client = libtaxii.scripts.fulfillment_client:main',
79 | 'inbox_client = libtaxii.scripts.inbox_client:main',
80 | 'inbox_client_10 = libtaxii.scripts.inbox_client_10:main',
81 | 'poll_client = libtaxii.scripts.poll_client:main',
82 | 'query_client = libtaxii.scripts.query_client:main',
83 | 'discovery_client_10 = libtaxii.scripts.discovery_client_10:main',
84 | 'feed_information_client_10 = libtaxii.scripts.feed_information_client_10:main',
85 | 'poll_client_10 = libtaxii.scripts.poll_client_10:main',
86 | ],
87 | },
88 | package_data={'libtaxii': ['xsd/*.xsd']},
89 | long_description=get_long_description(),
90 | keywords='taxii libtaxii',
91 | classifiers=[
92 | 'Development Status :: 5 - Production/Stable',
93 | 'Intended Audience :: Developers',
94 | 'License :: OSI Approved :: BSD License',
95 | 'Operating System :: OS Independent',
96 | 'Programming Language :: Python :: 2',
97 | 'Programming Language :: Python :: 2.6',
98 | 'Programming Language :: Python :: 2.7',
99 | 'Programming Language :: Python :: 3',
100 | 'Programming Language :: Python :: 3.3',
101 | 'Programming Language :: Python :: 3.4',
102 | 'Programming Language :: Python :: 3.5',
103 | 'Programming Language :: Python :: 3.6',
104 | 'Programming Language :: Python :: 3.7',
105 | 'Programming Language :: Python :: 3.8',
106 | ],
107 | project_urls={
108 | 'Documentation': 'https://libtaxii.readthedocs.io/',
109 | 'Source Code': 'https://github.com/TAXIIProject/libtaxii/',
110 | 'Bug Tracker': 'https://github.com/TAXIIProject/libtaxii/issues/',
111 | },
112 | )
113 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | envlist = py26, py27, rhel26, py34, py35, py36, py37, py38, docs, packaging
3 |
4 | [testenv]
5 | commands =
6 | pytest libtaxii
7 | sphinx-build -b doctest docs docs/_build/doctest
8 | sphinx-build -b html docs docs/_build/html
9 | deps = -rrequirements.txt
10 |
11 | [testenv:py26]
12 | commands =
13 | pytest libtaxii
14 | deps = pytest
15 |
16 | [testenv:rhel26]
17 | commands =
18 | pytest libtaxii
19 | deps =
20 | lxml==2.2.3
21 | python-dateutil==1.4.1
22 | six==1.9.0
23 | pytest
24 |
25 | [testenv:docs]
26 | commands =
27 | sphinx-build -b doctest docs docs/_build/doctest
28 | sphinx-build -b html docs docs/_build/html
29 |
30 | [testenv:packaging]
31 | deps =
32 | readme_renderer
33 | commands =
34 | python setup.py check -r -s
35 |
36 | [travis]
37 | python =
38 | 2.6: py26, rhel26
39 | 2.7: py27, docs, packaging
40 | 3.4: py34
41 | 3.5: py35
42 | 3.6: py36, docs, packaging
43 | 3.7: py37
44 | 3.8: py38
45 |
--------------------------------------------------------------------------------