From f5c975f16eb0c1449286f17465158ca680339621 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Mon, 19 Feb 2018 14:48:33 -0500 Subject: [PATCH 1/9] Add location object, Pools and everything under. Update bindings --- cybox/bindings/cybox_common.py | 3 +- cybox/bindings/cybox_core.py | 10 +++--- cybox/common/location.py | 25 +++++++++++++++ cybox/core/pool.py | 51 ++++++++++++++++++++++++++++++ cybox/test/common/location_test.py | 15 +++++++++ 5 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 cybox/common/location.py create mode 100644 cybox/core/pool.py create mode 100644 cybox/test/common/location_test.py diff --git a/cybox/bindings/cybox_common.py b/cybox/bindings/cybox_common.py index 095d318c..94b2fbb5 100644 --- a/cybox/bindings/cybox_common.py +++ b/cybox/bindings/cybox_common.py @@ -220,6 +220,7 @@ def exportChildren(self, lwrite, level, namespace_='cyboxCommon:', name_='Locati else: eol_ = '' if self.Name is not None: + showIndent(lwrite, level, pretty_print) lwrite('<%sName>%s%s' % ('cyboxCommon:', self.gds_format_string(quote_xml(self.Name), input_name='Name'), 'cyboxCommon:', eol_)) def build(self, node): self.__sourcenode__ = node @@ -241,7 +242,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Name': Name_ = child_.text Name_ = self.gds_validate_string(Name_, node, 'Name') - self.Name = Name_ + self.set = Name_ # end class LocationType class MeasureSourceType(GeneratedsSuper): diff --git a/cybox/bindings/cybox_core.py b/cybox/bindings/cybox_core.py index bc7484f0..ee3eacd0 100644 --- a/cybox/bindings/cybox_core.py +++ b/cybox/bindings/cybox_core.py @@ -3193,7 +3193,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Event': obj_ = EventType.factory() obj_.build(child_) - self.Event.append(obj_) + self.add_Event(obj_) # end class EventPoolType class ActionPoolType(GeneratedsSuper): @@ -3266,7 +3266,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Action': obj_ = ActionType.factory() obj_.build(child_) - self.Action.append(obj_) + self.add_Action(obj_) # end class ActionPoolType class ObjectPoolType(GeneratedsSuper): @@ -3339,7 +3339,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Object': obj_ = ObjectType.factory() obj_.build(child_) - self.set_Object(obj_) + self.add_Object(obj_) # end class ObjectPoolType class PropertyPoolType(GeneratedsSuper): @@ -3410,9 +3410,9 @@ def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Property': - obj_ = ActionPertinentObjectPropertyType.factory() + obj_ = cybox_common.PropertyType.factory() obj_.build(child_) - self.Property.append(obj_) + self.add_Property(obj_) # end class PropertyPoolType class ObfuscationTechniquesType(GeneratedsSuper): diff --git a/cybox/common/location.py b/cybox/common/location.py new file mode 100644 index 00000000..e6db8d09 --- /dev/null +++ b/cybox/common/location.py @@ -0,0 +1,25 @@ +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. + +from mixbox import entities, fields + +import cybox.bindings.cybox_common as common_binding + + +class Location(entities.Entity): + _binding = common_binding + _binding_class = common_binding.LocationType + _namespace = 'http://cybox.mitre.org/common-2' + _XSI_TYPE = None # overridden by subclasses + + id_ = fields.IdrefField("id") + idref = fields.IdrefField("idref") + name = fields.TypedField("Name") + + def to_dict(self): + d = super(Location, self).to_dict() + + if self._XSI_TYPE: + d["xsi:type"] = self._XSI_TYPE + + return d diff --git a/cybox/core/pool.py b/cybox/core/pool.py new file mode 100644 index 00000000..f25bf269 --- /dev/null +++ b/cybox/core/pool.py @@ -0,0 +1,51 @@ +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. + +from mixbox import entities, fields + +import cybox.bindings.cybox_core as core_binding +from cybox.common import Property +from cybox.core import Action, Event, Object + + +class EventPool(entities.Entity): + _binding = core_binding + _binding_class = _binding.EventPoolType + _namespace = 'http://cybox.mitre.org/cybox-2' + + events = fields.TypedField("Event", Event, multiple=True, key_name="events") + + +class ActionPool(entities.Entity): + _binding = core_binding + _binding_class = _binding.ActionPoolType + _namespace = 'http://cybox.mitre.org/cybox-2' + + actions = fields.TypedField("Action", Action, multiple=True, key_name="actions") + + +class ObjectPool(entities.Entity): + _binding = core_binding + _binding_class = _binding.ObjectPoolType + _namespace = 'http://cybox.mitre.org/cybox-2' + + objects = fields.TypedField("Object", Object, multiple=True, key_name="objects") + + +class PropertyPool(entities.Entity): + _binding = core_binding + _binding_class = _binding.PropertyPoolType + _namespace = 'http://cybox.mitre.org/cybox-2' + + properties = fields.TypedField("Property", Property, multiple=True, key_name="properties") + + +class Pools(entities.Entity): + _binding = core_binding + _binding_class = _binding.PoolsType + _namespace = 'http://cybox.mitre.org/cybox-2' + + event_pool = fields.TypedField("Event_Pool", EventPool) + action_pool = fields.TypedField("Action_Pool", ActionPool) + object_pool = fields.TypedField("Object_Pool", ObjectPool) + property_pool = fields.TypedField("Property_Pool", PropertyPool) diff --git a/cybox/test/common/location_test.py b/cybox/test/common/location_test.py new file mode 100644 index 00000000..0a19feec --- /dev/null +++ b/cybox/test/common/location_test.py @@ -0,0 +1,15 @@ +# Copyright (c) 2017, The MITRE Corporation. All rights reserved. +# See LICENSE.txt for complete terms. + +import unittest + +from cybox.common import Location +import cybox.test + + +class TestLocation(cybox.test.EntityTestCase, unittest.TestCase): + klass = Location + _full_dict = { + 'name': "Bedford, MA", + 'id': "example:12345", + } From d27aec47252eda6c7d4178fe6c2869ea4a710638 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Mon, 19 Feb 2018 14:49:17 -0500 Subject: [PATCH 2/9] Expose new objects --- cybox/common/__init__.py | 1 + cybox/core/__init__.py | 1 + 2 files changed, 2 insertions(+) diff --git a/cybox/common/__init__.py b/cybox/common/__init__.py index 96719ab7..07a43612 100644 --- a/cybox/common/__init__.py +++ b/cybox/common/__init__.py @@ -34,6 +34,7 @@ from .digitalsignature import DigitalSignature, DigitalSignatureList from .environment_variable import EnvironmentVariable, EnvironmentVariableList from .hashes import Hash, HashList, HashName +from .location import Location from .object_properties import ObjectProperties, Property from .structured_text import StructuredText from .time import Time diff --git a/cybox/core/__init__.py b/cybox/core/__init__.py index 1e49caf5..51e4160d 100644 --- a/cybox/core/__init__.py +++ b/cybox/core/__init__.py @@ -17,4 +17,5 @@ from .event import Event, EventType from .pattern_fidelity import (PatternFidelity, ObfuscationTechniques, ObfuscationTechnique) +from .pool import ActionPool, EventPool, PropertyPool, ObjectPool, Pools from .observable import Observable, Observables, ObservableComposition From 8e49e4b48c4da1ff6bcd0663afaeb8ce48dd34ce Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Mon, 19 Feb 2018 14:50:29 -0500 Subject: [PATCH 3/9] Formatting changes to Action and Object --- cybox/core/action.py | 4 +++- cybox/core/object.py | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/cybox/core/action.py b/cybox/core/action.py index 0eddec3c..7810dcd8 100644 --- a/cybox/core/action.py +++ b/cybox/core/action.py @@ -43,6 +43,7 @@ class AssociatedObjects(entities.EntityList): _namespace = 'http://cybox.mitre.org/cybox-2' associated_object = fields.TypedField("Associated_Object", AssociatedObject, multiple=True) + class ActionRelationship(entities.Entity): _binding = core_binding _binding_class = _binding.ActionRelationshipType @@ -59,6 +60,7 @@ class ActionRelationships(entities.EntityList): _namespace = 'http://cybox.mitre.org/cybox-2' relationship = fields.TypedField("Relationship", ActionRelationship, multiple=True) + class Action(entities.Entity): _binding = core_binding _binding_class = core_binding.ActionType @@ -84,4 +86,4 @@ class Action(entities.Entity): class Actions(entities.EntityList): _binding_class = core_binding.ActionsType _namespace = 'http://cybox.mitre.org/cybox-2' - action = fields.TypedField("Action", Action, multiple=True) \ No newline at end of file + action = fields.TypedField("Action", Action, multiple=True) diff --git a/cybox/core/object.py b/cybox/core/object.py index 610aa63b..061d2791 100644 --- a/cybox/core/object.py +++ b/cybox/core/object.py @@ -210,5 +210,8 @@ def to_obj(self, ns_info=None): def to_dict(self): d = super(DomainSpecificObjectProperties, self).to_dict() - d['xsi:type'] = self._XSI_TYPE + + if self._XSI_TYPE: + d['xsi:type'] = self._XSI_TYPE + return d From 072494f50d9bfa2a8a5ba05e0a717726545e350e Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Mon, 19 Feb 2018 14:52:44 -0500 Subject: [PATCH 4/9] Add location to Event. Add Pools to Observables and update add() method. Update tests --- cybox/core/event.py | 4 +- cybox/core/observable.py | 26 +++++---- cybox/test/core/event_test.py | 4 ++ cybox/test/core/observable_test.py | 94 ++++++++++++++++++++++++++++++ 4 files changed, 114 insertions(+), 14 deletions(-) diff --git a/cybox/core/event.py b/cybox/core/event.py index 2f3bee52..a7941d9d 100644 --- a/cybox/core/event.py +++ b/cybox/core/event.py @@ -5,7 +5,7 @@ from mixbox import fields import cybox.bindings.cybox_core as core_binding -from cybox.common import StructuredText, MeasureSource +from cybox.common import StructuredText, MeasureSource, Location from cybox.common.vocabs import EventType, VocabField from cybox.core import Actions, Frequency @@ -23,7 +23,7 @@ class Event(entities.Entity): observation_method = fields.TypedField("Observation_Method", MeasureSource) actions = fields.TypedField("Actions", Actions) frequency = fields.TypedField("Frequency", Frequency) - + location = fields.TypedField("Location", Location) event = fields.TypedField("Event", multiple=True) # Allow recursive definition of events diff --git a/cybox/core/observable.py b/cybox/core/observable.py index 1bee49c0..4a2b0c4d 100644 --- a/cybox/core/observable.py +++ b/cybox/core/observable.py @@ -1,10 +1,7 @@ # Copyright (c) 2017, The MITRE Corporation. All rights reserved. # See LICENSE.txt for complete terms. -import collections -from mixbox import entities -from mixbox import fields -from mixbox import idgen +from mixbox import entities, fields, idgen from cybox import Unicode import cybox.bindings.cybox_core as core_binding @@ -127,8 +124,6 @@ def add_keyword(self, value): class Observables(entities.EntityList): """The root CybOX Observables object. - - Pools are not currently supported. """ _binding = core_binding _binding_class = _binding.ObservablesType @@ -136,6 +131,7 @@ class Observables(entities.EntityList): observable_package_source = fields.TypedField("Observable_Package_Source", MeasureSource) observables = fields.TypedField("Observable", Observable, multiple=True, key_name="observables") + pools = fields.TypedField("Pools", type_="cybox.core.pool.Pools") def __init__(self, observables=None): super(Observables, self).__init__(observables) @@ -144,12 +140,19 @@ def __init__(self, observables=None): self._minor_version = 1 self._update_version = 0 - def add(self, observable): - if not observable: + def add(self, object_): + from cybox.core.pool import Pools + if not object_: return - if not isinstance(observable, Observable): - observable = Observable(observable) - self.observables.append(observable) + elif isinstance(object_, MeasureSource): + self.observable_package_source = object_ + return + elif isinstance(object_, Pools): + self.pools = object_ + return + elif not isinstance(object_, Observable): + object_ = Observable(object_) + self.observables.append(object_) def to_obj(self, ns_info=None): observables_obj = super(Observables, self).to_obj(ns_info=ns_info) @@ -190,4 +193,3 @@ def add(self, observable): if not observable: raise ValueError("'observable' must not be None") self.append(observable) - diff --git a/cybox/test/core/event_test.py b/cybox/test/core/event_test.py index 62791b00..71b0fd68 100644 --- a/cybox/test/core/event_test.py +++ b/cybox/test/core/event_test.py @@ -23,6 +23,10 @@ class TestEvent(EntityTestCase, unittest.TestCase): {'idref': "example:Action-5"}, {'idref': "example:Action-6"}, ], + 'location': { + 'name': "Some location", + 'id': "example:Location-A" + }, # Once the choice is implemented, this won't work 'event': [ {'idref': "example:Event-A"}, diff --git a/cybox/test/core/observable_test.py b/cybox/test/core/observable_test.py index 17ee840e..d9ce9a0a 100644 --- a/cybox/test/core/observable_test.py +++ b/cybox/test/core/observable_test.py @@ -222,6 +222,100 @@ class TestObservables(EntityTestCase, unittest.TestCase): 'name': "The Source", 'information_source_type': u("Logs"), }, + 'pools': { + 'event_pool': { + 'events': [ + { + 'id': "example:Event-1", + 'idref': "example:Event-2", + 'type': u("Port Scan"), + 'description': u("This is a test event"), + 'observation_method': {'class': "Network"}, + 'frequency': {'rate': 1.0}, + 'actions': [ + {'idref': "example:Action-5"}, + {'idref': "example:Action-6"}, + ], + 'location': { + 'name': "Some location", + 'id': "example:Location-A" + }, + # Once the choice is implemented, this won't work + 'event': [ + {'idref': "example:Event-A"}, + {'idref': "example:Event-B"}, + ] + } + ] + }, + 'action_pool': { + 'actions': [ + { + 'id': "example:Action-1", + 'idref': "example:Action-2", + 'ordinal_position': 42, + 'action_status': "Success", + 'context': "Host", + 'timestamp': "2013-10-24T09:54:13", + 'type': u("Modify"), + 'name': u("Modify File"), + 'description': {'value': "An action!", + 'structuring_format': "Text"}, + 'action_aliases': ['an alias', 'another_alias'], + 'action_arguments': [ + { + 'argument_name': u("infile"), + 'argument_value': "/tmp/somefile.txt", + }, + { + 'argument_name': u("outfile"), + 'argument_value': "/tmp/someotherfile.txt", + } + ], + 'discovery_method': {'name': "A tool"}, + 'associated_objects': [ + { + 'idref': "example:File-1", + } + ], + 'relationships': [ + { + 'type': u("Followed_By"), + 'action_reference': [{'action_id': "example:Action-2"}] + } + ], + 'frequency': {'rate': 1.0} + } + ] + }, + 'object_pool': { + 'objects': [ + { + 'id': "example:Object-1", + 'properties': { + 'file_name': u("example.txt"), + 'xsi:type': "FileObjectType" + }, + 'related_objects': [ + { + 'idref': "example:Object-2", + 'relationship': u("Same As"), + }, + ] + } + ] + }, + 'property_pool': { + 'properties': [ + { + 'id': "example:Property-1", + 'name': "FilePurpose", + 'description': "The purpose of the file", + 'value': u("Certificate") + } + ] + } + } } # https://github.com/CybOXProject/python-cybox/issues/232 From ccc7d22da8807aeccb65e01d1c67ffb1ab9f1b96 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Mon, 19 Feb 2018 15:06:03 -0500 Subject: [PATCH 5/9] Fix typo in bindings --- cybox/bindings/cybox_common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cybox/bindings/cybox_common.py b/cybox/bindings/cybox_common.py index 94b2fbb5..6fe71bd7 100644 --- a/cybox/bindings/cybox_common.py +++ b/cybox/bindings/cybox_common.py @@ -242,7 +242,7 @@ def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'Name': Name_ = child_.text Name_ = self.gds_validate_string(Name_, node, 'Name') - self.set = Name_ + self.Name = Name_ # end class LocationType class MeasureSourceType(GeneratedsSuper): From 8d3f80533c8cc17ef2812956a11f670e4443317b Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Mon, 26 Feb 2018 14:42:09 -0500 Subject: [PATCH 6/9] Fix VocabString.is_plain(). closes #313 --- cybox/common/vocabs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cybox/common/vocabs.py b/cybox/common/vocabs.py index 6bdc6a61..7507e304 100644 --- a/cybox/common/vocabs.py +++ b/cybox/common/vocabs.py @@ -120,7 +120,7 @@ def is_plain(self): """ return ( - (self.xsi_type is None or type(self)._XSI_TYPE == self.xsi_type) and + self.xsi_type is None and self.vocab_name is None and self.vocab_reference is None and super(VocabString, self).is_plain() @@ -149,6 +149,7 @@ def from_obj(cls, cls_obj): #: Mapping of Controlled Vocabulary xsi:type's to their class implementations. _VOCAB_MAP = {} + def _get_terms(vocab_class): """Helper function used by register_vocab.""" for k, v in vocab_class.__dict__.items(): From f112debfdbce2cb53edb36d0edc2be79d9723c0e Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 28 Feb 2018 13:36:13 -0500 Subject: [PATCH 7/9] Add tests for VocabString.is_plain() --- cybox/test/common/vocab_test.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cybox/test/common/vocab_test.py b/cybox/test/common/vocab_test.py index 742b6705..f4f907db 100644 --- a/cybox/test/common/vocab_test.py +++ b/cybox/test/common/vocab_test.py @@ -146,6 +146,16 @@ def test_to_dict(self): else: self.assertEqual(d, ActionName.TERM_ADD_USER) + def test_vocab_is_plain_false(self): + from cybox.common.vocabs import ActionName + action = ActionName(ActionName.TERM_ADD_USER) + self.assertFalse(action.is_plain()) + + def test_vocab_is_plain_true(self): + from cybox.common.vocabs import VocabString + vocab = VocabString(value="foo") + self.assertTrue(vocab.is_plain()) + class HashNameTests(unittest.TestCase): From f3f84b621c0861b0be5f7420a60b4f50f898a129 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 28 Feb 2018 13:39:17 -0500 Subject: [PATCH 8/9] Update tools_test.py --- cybox/test/common/tools_test.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cybox/test/common/tools_test.py b/cybox/test/common/tools_test.py index 4666fc7b..1e043e83 100644 --- a/cybox/test/common/tools_test.py +++ b/cybox/test/common/tools_test.py @@ -18,7 +18,16 @@ class TestToolInformation(EntityTestCase, unittest.TestCase): 'id': "example:Tool-A1", # 'idref': "example:Tool-A1-ref", # CAnnot set both an id and idref 'name': "AwesomeTool(tm)", - 'type': [u('NIDS'), u('HIPS')], + 'type': [ + { + 'value': u('NIDS'), + 'xsi:type': 'cyboxVocabs:ToolTypeVocab-1.1' + }, + { + 'value': u('HIPS'), + 'xsi:type': 'cyboxVocabs:ToolTypeVocab-1.1' + } + ], 'description': {'structuring_format': 'HTML', 'value': '

An awesome tool!

'}, From 9fdbbf1ee0ceb6d33f0e73e488a2bb4a2881e183 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Wed, 28 Feb 2018 13:44:01 -0500 Subject: [PATCH 9/9] More fixes to vocab_test.py --- cybox/test/common/vocab_test.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cybox/test/common/vocab_test.py b/cybox/test/common/vocab_test.py index f4f907db..a8e2bcb9 100644 --- a/cybox/test/common/vocab_test.py +++ b/cybox/test/common/vocab_test.py @@ -139,12 +139,8 @@ def test_add_vocabstring(self): def test_to_dict(self): from cybox.common.vocabs import ActionName d = ActionName(ActionName.TERM_ADD_USER).to_dict() - if 'xsi:type' in d: - self.assertEqual(d['xsi:type'], ActionName._XSI_TYPE) - if 'value' in d: - self.assertEqual(d['value'], ActionName.TERM_ADD_USER) - else: - self.assertEqual(d, ActionName.TERM_ADD_USER) + self.assertEqual(d['xsi:type'], ActionName._XSI_TYPE) + self.assertEqual(d['value'], ActionName.TERM_ADD_USER) def test_vocab_is_plain_false(self): from cybox.common.vocabs import ActionName