Skip to content

Commit

Permalink
Merge pull request #305 from STIXProject/issue302
Browse files Browse the repository at this point in the history
Handle CIQ Identities correctly
  • Loading branch information
gtback committed Oct 6, 2016
2 parents 12db53e + 21a1b1e commit 06d4b5a
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 11 deletions.
1 change: 0 additions & 1 deletion stix/bindings/extensions/identity/ciq_identity_3_0.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ class CIQIdentity3_0InstanceType(stix_common_binding.IdentityType):

def __init__(self, idref=None, id=None, Name=None, Related_Identities=None, Specification=None, Role=None):
super(CIQIdentity3_0InstanceType, self).__init__(idref=idref, id=id, Name=Name, Related_Identities=Related_Identities)
self.xsi_type = None
self.Specification = Specification
if Role is None:
self.Role = []
Expand Down
1 change: 0 additions & 1 deletion stix/bindings/stix_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -1283,7 +1283,6 @@ def __init__(self, idref=None, id=None, Name=None, Related_Identities=None):
self.id = _cast(None, id)
self.Name = Name
self.Related_Identities = Related_Identities
self.xsi_type = None
def factory(*args_, **kwargs_):
if IdentityType.subclass:
return IdentityType.subclass(*args_, **kwargs_)
Expand Down
13 changes: 12 additions & 1 deletion stix/common/identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ def entity_class(cls, key):

class Identity(stix.Entity):
_binding = common_binding
_namespace = 'http://stix.mitre.org/common-1'
_binding_class = IdentityType
_namespace = 'http://stix.mitre.org/common-1'

id_ = fields.IdField("id")
idref = fields.IdrefField("idref")
Expand All @@ -36,6 +36,17 @@ def __init__(self, id_=None, idref=None, name=None, related_identities=None):
self.name = name
self.related_identities = related_identities

def to_dict(self):
d = super(Identity, self).to_dict()

if self._XSI_TYPE:
d['xsi:type'] = self._XSI_TYPE

return d

@staticmethod
def lookup_class(xsi_type):
return stix.lookup_extension(xsi_type, default=Identity)

# We can't import RelatedIdentity until we have defined the Identity class.
from stix.common.related import RelatedIdentity
Expand Down
57 changes: 56 additions & 1 deletion stix/test/extensions/identity/ciq_identity_3_0_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@
# See LICENSE.txt for complete terms.

import unittest
from stix.test import EntityTestCase
from mixbox.vendor.six import BytesIO, text_type

from stix.threat_actor import ThreatActor
import stix.extensions.identity.ciq_identity_3_0 as ciq
from stix.test import EntityTestCase
from stix.core import STIXPackage


class CIQIdentity3_0InstanceTests(EntityTestCase, unittest.TestCase):
Expand Down Expand Up @@ -108,5 +112,56 @@ class CIQIdentity3_0InstanceTests(EntityTestCase, unittest.TestCase):
}


class IdentityInThreatActorTests(EntityTestCase, unittest.TestCase):
klass = ThreatActor
_full_dict = {
"id": "example:threatactor-c96266cf-ccb3-43f3-b44e-26dbd66273e5",
"identity": {
"specification": {
"addresses": [
{
"administrative_area": {
"name_elements": [{"value": "California"}
]
},
"country": {
"name_elements": [{"value": "United States"}]
}
}
],
"electronic_address_identifiers": [
{"value": "disco-team@stealthemail.com"},
{"value": "facebook.com/thediscoteam"},
{"value": "twitter.com/realdiscoteam"}
],
"languages": [{"value": "Spanish"}],
"party_name": {
"organisation_names": [
{
"name_elements": [{"value": "Disco Tean"}],
"type": "CommonUse"
},
{
"name_elements": [{"value": "Equipo del Discoteca"}],
"type": "UnofficialName"
}
]
}
},
"xsi:type": "ciqIdentity:CIQIdentity3.0InstanceType"
},
"timestamp": "2016-10-04T19:43:57.382126+00:00",
"title": "Disco Team Threat Actor Group"
}

def test_identity_from_xml(self):
obj = self.klass.from_dict(self._full_dict)
sp = STIXPackage()
sp.add(obj)
s = BytesIO(sp.to_xml())
pkg = STIXPackage.from_xml(s)
self.assertTrue("CIQIdentity3.0InstanceType" in text_type(pkg.to_xml()))


if __name__ == "__main__":
unittest.main()
28 changes: 28 additions & 0 deletions stix/test/ttp_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from stix.test import EntityTestCase, assert_warnings
from stix.test import data_marking_test
from stix.test.common import related_test, identity_test, kill_chains_test
from stix.test.extensions.identity import ciq_identity_3_0_test

from stix.core import STIXPackage
import stix.ttp as ttp
Expand Down Expand Up @@ -34,6 +35,14 @@ class PersonasTests(EntityTestCase, unittest.TestCase):
]


class PersonasWithCIQTests(EntityTestCase, unittest.TestCase):
klass = resource.Personas

_full_dict = [
ciq_identity_3_0_test.CIQIdentity3_0InstanceTests._full_dict
]


class InfrastructureTests(EntityTestCase, unittest.TestCase):
klass = infrastructure.Infrastructure

Expand Down Expand Up @@ -194,5 +203,24 @@ def test_deprecated_related_packages(self):
self.assertEqual(len(t.related_packages), 1)


class TTPIdentityTests(EntityTestCase, unittest.TestCase):
klass = ttp.TTP
_full_dict = {
"id": "example:ttp-775591f7-7e01-4546-9522-d4211df4aac7",
"timestamp": "2016-10-04T19:57:44.446575+00:00",
"title": "Victim Targeting: Electricity Sector and Industrial Control System Sector",
"victim_targeting": {
"identity": {
"specification": {
"organisation_info": {
"industry_type": "Electricity, Industrial Control Systems"
}
},
"xsi:type": "ciqIdentity:CIQIdentity3.0InstanceType"
}
}
}


if __name__ == "__main__":
unittest.main()
5 changes: 3 additions & 2 deletions stix/threat_actor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
# internal
import stix
import stix.bindings.threat_actor as threat_actor_binding
from stix.common import vocabs, Confidence, Identity, Statement
from stix.common import vocabs, Confidence, Statement
from stix.common.identity import Identity, IdentityFactory
from stix.common.related import (
GenericRelationshipList, RelatedCampaign, RelatedPackageRefs, RelatedTTP,
RelatedThreatActor
Expand Down Expand Up @@ -65,7 +66,7 @@ class ThreatActor(stix.BaseCoreComponent):
_ALL_VERSIONS = ("1.0", "1.0.1", "1.1", "1.1.1", "1.2")
_ID_PREFIX = 'threatactor'

identity = fields.TypedField("Identity", Identity)
identity = fields.TypedField("Identity", Identity, factory=IdentityFactory)
types = StatementField("Type", Statement, vocab_type=vocabs.ThreatActorType, multiple=True, key_name="types")
motivations = StatementField("Motivation", Statement, vocab_type=vocabs.Motivation, multiple=True, key_name="motivations")
sophistications = StatementField("Sophistication", Statement, vocab_type=vocabs.ThreatActorSophistication, multiple=True, key_name="sophistications")
Expand Down
5 changes: 3 additions & 2 deletions stix/ttp/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

# internal
import stix
from stix.common import ToolInformation, Identity
from stix.common import ToolInformation
from stix.common.identity import Identity, IdentityFactory
import stix.bindings.ttp as ttp_binding

# relative
Expand All @@ -28,7 +29,7 @@ class Personas(stix.EntityList):
_binding = ttp_binding
_binding_class = _binding.PersonasType

persona = fields.TypedField("Persona", Identity, multiple=True, listfunc=_IdentityList)
persona = fields.TypedField("Persona", Identity, multiple=True, factory=IdentityFactory, listfunc=_IdentityList)


class Tools(stix.EntityList):
Expand Down
8 changes: 5 additions & 3 deletions stix/ttp/victim_targeting.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@

# internal
import stix
from stix.common import vocabs, VocabString, Identity
import stix.bindings.ttp as ttp_binding
from stix.common import vocabs, VocabString
from stix.common.identity import Identity, IdentityFactory
from mixbox import fields


class VictimTargeting(stix.Entity):
_binding = ttp_binding
_binding_class = _binding.VictimTargetingType
_namespace = "http://stix.mitre.org/TTP-1"

identity = fields.TypedField("Identity", Identity)
identity = fields.TypedField("Identity", Identity, factory=IdentityFactory)

targeted_systems = vocabs.VocabField("Targeted_Systems", vocabs.SystemType, multiple=True)
targeted_information = vocabs.VocabField("Targeted_Information", vocabs.InformationType, multiple=True)

Expand Down

0 comments on commit 06d4b5a

Please sign in to comment.