Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New API Objects Support #329

Merged
merged 36 commits into from
Mar 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
5a76c28
fix object inheritance for OS object and system-ref to use correct na…
emmanvg Dec 4, 2019
d4ef651
implement ObjectStateVocab
emmanvg Dec 4, 2019
01e52e2
Full support for SystemObject
emmanvg Dec 4, 2019
051470e
update Tox/Travis CI configuration
emmanvg Feb 21, 2020
8910d09
create API Objects for NetworkFlow
emmanvg Feb 21, 2020
62009eb
rename win_user_object.py -> win_user_account_object.py for consistency
emmanvg Feb 21, 2020
1cf4d91
minor edits to custom_object.py and win_file_object.py
emmanvg Feb 21, 2020
ac10874
implement a few of the missing properties for: Archive, ARPCache, Dev…
emmanvg Feb 21, 2020
3c0e466
implement new API Objects: UnixFile, UnixNetworkRouteEntry, UnixPipe,…
emmanvg Feb 21, 2020
db0209f
update OBJ_LIST to capture new API Objects
emmanvg Feb 21, 2020
0404cae
provide API Object extension mechanism similar to python-stix
emmanvg Feb 21, 2020
de43afe
NetworkFlow -> update bindings to generate proper objects
emmanvg Feb 21, 2020
74eaffe
fix nsparser.py and add UserSession
emmanvg Feb 21, 2020
9041165
add UnixProcess binding ability to express its xsi:type and register …
emmanvg Feb 21, 2020
c0f29a5
register UnixFilePermissions binding
emmanvg Feb 21, 2020
d3676ed
cybox_core.py bindings import UserSession binding
emmanvg Feb 21, 2020
e7a29ef
create register extension mechanism for bindings similar to python-stix
emmanvg Feb 21, 2020
76fcfae
implement DefinedEffect API Object and all extensions
emmanvg Feb 21, 2020
24984fa
minor changes to action.py and event.py
emmanvg Feb 21, 2020
046ab6f
implement more properties on Object and Observable
emmanvg Feb 21, 2020
0d1252c
minor details on common/ datetimewithprecision.py extracted_string.py…
emmanvg Feb 21, 2020
95a4460
provide location.py with Factory and extension mechanism. Implement m…
emmanvg Feb 21, 2020
f10bb74
new API Common Object implementations
emmanvg Feb 21, 2020
9fddc7a
fix 'GUIDialogBoxObj' ns
emmanvg Mar 4, 2020
42b3b16
minor edits throughout existing tests:
emmanvg Mar 5, 2020
334d7ef
Added 23 new Test Classes for missing objects or new objects
emmanvg Mar 5, 2020
c89ef3d
fixes to API objects or bindings found on testing
emmanvg Mar 5, 2020
5e604a3
add test for DefinedEffect, minor formatting fixes
emmanvg Mar 5, 2020
0e9daf6
update documentation to include all new implemented objects or missin…
emmanvg Mar 5, 2020
513f1ad
implement the actual TestWinService test case
emmanvg Mar 6, 2020
1321541
implement the actual TestWinExecutableFile test case
emmanvg Mar 6, 2020
1a98558
update TestArchiveFile test to include 'archived_file'
emmanvg Mar 6, 2020
2757c46
move extension maps to the actual classes for artifact_object.py
emmanvg Mar 6, 2020
9255b46
fix import issue archive_file_object.py
emmanvg Mar 6, 2020
b4940df
fix win_executable_file_object.py API and bindings
emmanvg Mar 6, 2020
242e128
add 'network_route_entries' in network_route_test.py
emmanvg Mar 6, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
language: python
sudo: false # Since this is an older project, this is not the default.
cache: pip
dist: xenial
python:
Expand All @@ -8,6 +7,7 @@ python:
- "3.5"
- "3.6"
- "3.7"
- "3.8"
install:
- pip install -U pip setuptools
- pip install tox-travis
Expand Down
121 changes: 119 additions & 2 deletions cybox/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,130 @@
# Copyright (c) 2017, The MITRE Corporation. All rights reserved.
# Copyright (c) 2020, The MITRE Corporation. All rights reserved.
# See LICENSE.txt for complete terms.

from mixbox import entities
from mixbox.vendor import six

from .version import __version__ # noqa

#: Mapping of xsi:types to implementation/extension classes
_EXTENSION_MAP = {}

#TODO: Should this get moved to mixbox or not?

def _lookup_unprefixed(typename):
"""Attempts to resolve a class for the input XML type `typename`.

Args:
typename: The name of an CybOX XML type (e.g., UnixProcessStatusType)
without a namespace prefix.

Returns:
A stix.Entity implementation class for the `typename`.


Raises:
ValueError: If no class has been registered for the input `typename`.

"""
for xsi_type, klass in six.iteritems(_EXTENSION_MAP):
if typename in xsi_type:
return klass

error = "Unregistered extension type: %s" % typename
raise ValueError(error)


def _lookup_extension(xsi_type):
"""Returns a Python class for the `xsi_type` value.

Args:
xsi_type: An xsi:type value string.

Returns:
An Entity implementation class for the `xsi_type`.

Raises:
ValueError: If no class has been registered for the `xsi_type`.

"""
if xsi_type in _EXTENSION_MAP:
return _EXTENSION_MAP[xsi_type]

raise ValueError("Unregistered xsi:type %s" % xsi_type)


def lookup_extension(typeinfo, default=None):
"""Returns an Entity class for that has been registered for the
`typeinfo` value.

Note:
This is for internal use only.

Args:
typeinfo: An object or string containing type information. This can be
either an xsi:type attribute value or a stix.bindings object.
default: Return class if typeinfo is None or contains no xml type
information.

Returns:
An Entity implementation class for the `xsi_type`.

Raises:
ValueError: If no class has been registered for the `xsi_type`.

"""
if typeinfo is None and default:
return default

# If the `typeinfo` was a string, consider it a full xsi:type value.
if isinstance(typeinfo, six.string_types):
return _lookup_extension(typeinfo)

# Most extension bindings include this attribute.
if not hasattr(typeinfo, 'xml_type'):
if default:
return default

error = "Input %s is missing xml_type attribute. Cannot lookup class."
raise ValueError(error % type(typeinfo))

# Extension binding classes usually (always?) have an `xmlns_prefix`
# class attribute.
if hasattr(typeinfo, 'xmlns_prefix'):
xsi_type = "%s:%s" % (typeinfo.xmlns_prefix, typeinfo.xml_type)
return _lookup_extension(xsi_type)

# no xmlns_prefix found, try to resolve the class by just the `xml_type`
return _lookup_unprefixed(typeinfo.xml_type)


def add_extension(cls):
"""Registers an Entity class as an implementation of an xml type.

Classes must have an ``_XSI_TYPE`` class attributes to be registered. The
value of this attribute must be a valid xsi:type.

Note:
This was designed for internal use.

"""
_EXTENSION_MAP[cls._XSI_TYPE] = cls # noqa


def register_extension(cls):
"""Class decorator for registering a stix.Entity class as an implementation
of an xml type.

Classes must have an ``_XSI_TYPE`` class attributes to be registered.

Note:
This was designed for internal use.

"""
add_extension(cls)
return cls


# TODO: Should this get moved to mixbox or not?
class Unicode(entities.Entity):
"""Shim class to allow xs:string's in EntityList"""

Expand Down
96 changes: 96 additions & 0 deletions cybox/bindings/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Copyright (c) 2020, The MITRE Corporation. All rights reserved.
# See LICENSE.txt for complete terms.

import collections

import mixbox.xml

TypeInfo = collections.namedtuple("TypeInfo", ('ns', 'typename'))


def get_type_info(node):
"""Returns a ``TypeInfo`` object for `node`.

This is accomplished by parsing the ``xsi:type`` attribute found on
`node`.

Args:
node: An lxml.etree element object.

Raises:
KeyError: If `node` does not have an ``xsi:type`` attribute.

"""
xsi_type = node.attrib[mixbox.xml.TAG_XSI_TYPE]
typeinfo = xsi_type.split(":")

if len(typeinfo) == 2:
prefix, typename = typeinfo
else:
typename = typeinfo
prefix = None

ns = node.nsmap[prefix]
return TypeInfo(ns=ns, typename=typename)


#: A mapping of namespace/type information to binding classes.
_BINDING_EXTENSION_MAP = {}


def add_extension(cls):
"""Adds the binding class `cls` to the ``_EXTENSION_MAP``.

This enables the lookup and instantiation of classes during parse when
``xsi:type`` attributes are encountered.

"""
typeinfo = TypeInfo(ns=cls.xmlns, typename=cls.xml_type)
_BINDING_EXTENSION_MAP[typeinfo] = cls


def register_extension(cls):
"""Class decorator for registering a binding class as an implementation of
an xml type.

Classes must have ``xmlns`` and ``xml_type`` class attributes to be
registered.

"""
add_extension(cls)
return cls


def lookup_extension(typeinfo, default=None):
"""Looks up the binding class for `typeinfo`, which is a namespace/typename
pairing.

Args:
typeinfo: An lxml Element node or a stix.bindings.TypeInfo namedtuple.
default: A binding class that will be returned if typeinfo is an
Element without an xsi:type attribute.

Returns:
A binding class that has been registered for the namespace and typename
found on `typeinfo`.

"""
if not isinstance(typeinfo, TypeInfo):
if has_xsi_type(typeinfo):
typeinfo = get_type_info(typeinfo)
elif default:
return default

if typeinfo in _BINDING_EXTENSION_MAP:
return _BINDING_EXTENSION_MAP[typeinfo]

fmt = "No class implemented or registered for XML type '{%s}%s'"
error = fmt % (typeinfo.ns, typeinfo.typename)
raise NotImplementedError(error)


def has_xsi_type(node):
"""Returns ``True`` if `node` does not have an xsi:type attribute.

"""
return mixbox.xml.TAG_XSI_TYPE in node.attrib
Loading