From b2c6acfbf6f03cc852f74df80d5569463a75a44c Mon Sep 17 00:00:00 2001 From: Greg Back Date: Thu, 21 Jun 2018 12:42:10 -0500 Subject: [PATCH] GH-188: Restrict valid UUID values. --- stix2/properties.py | 9 ++++-- stix2/test/test_properties.py | 54 +++++++++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/stix2/properties.py b/stix2/properties.py index 39d383a..33d3917 100644 --- a/stix2/properties.py +++ b/stix2/properties.py @@ -172,10 +172,13 @@ class IDProperty(Property): if not value.startswith(self.required_prefix): raise ValueError("must start with '{0}'.".format(self.required_prefix)) try: - uuid.UUID(value.split('--', 1)[1]) - except Exception: + type, orig_id = value.split('--', maxsplit=1) + new_uuid = uuid.UUID(orig_id) + if new_uuid.variant != uuid.RFC_4122 or new_uuid.version != 4: + raise ValueError() + except ValueError: raise ValueError("must have a valid UUID after the prefix.") - return value + return "--".join([type, str(new_uuid)]) def default(self): return self.required_prefix + str(uuid.uuid4()) diff --git a/stix2/test/test_properties.py b/stix2/test/test_properties.py index 16ff06a..68eae15 100644 --- a/stix2/test/test_properties.py +++ b/stix2/test/test_properties.py @@ -1,3 +1,5 @@ +import uuid + import pytest from stix2 import CustomObject, EmailMIMEComponent, ExtensionsProperty, TCPExt @@ -85,18 +87,58 @@ def test_type_property(): assert prop.clean(prop.default()) -def test_id_property(): - idprop = IDProperty('my-type') +ID_PROP = IDProperty('my-type') +MY_ID = 'my-type--232c9d3f-49fc-4440-bb01-607f638778e7' - assert idprop.clean('my-type--90aaca8a-1110-5d32-956d-ac2f34a1bd8c') + +@pytest.mark.parametrize("value", [ + MY_ID, + 'my-type--00000000-0000-4000-8000-000000000000', +]) +def test_id_property_valid(value): + assert ID_PROP.clean(value) == value + + +@pytest.mark.parametrize("value", [ + # These are all acceptable input formats that will get translated to the + # same ID shown above + MY_ID, + # These formats are all used in the uuid.UUID() documentation as valid ways + # to initialize a UUID. We are ok with accepting them, as they will + # get coerced to the right format for an ID. + 'my-type--{232c9d3f-49fc-4440-bb01-607f638778e7}', + 'my-type--232c9d3f49fc4440bb01607f638778e7', + 'my-type--urn:uuid:232c9d3f-49fc-4440-bb01-607f638778e7', + # The extra "--" are ignored by split() and accepted by uuid.UUID() + 'my-type--232c9d3f--49fc--4440--bb01--607f638778e7', +]) +def test_id_property_transform(value): + assert ID_PROP.clean(value) == MY_ID + + +def test_id_property_wrong_type(): with pytest.raises(ValueError) as excinfo: - idprop.clean('not-my-type--90aaca8a-1110-5d32-956d-ac2f34a1bd8c') + ID_PROP.clean('not-my-type--232c9d3f-49fc-4440-bb01-607f638778e7') assert str(excinfo.value) == "must start with 'my-type--'." + + +@pytest.mark.parametrize("value", [ + 'my-type--foo', + # Not a v4 UUID + 'my-type--00000000-0000-0000-0000-000000000000', + 'my-type--' + str(uuid.uuid1()), + 'my-type--' + str(uuid.uuid3(uuid.NAMESPACE_DNS, "example.org")), + 'my-type--' + str(uuid.uuid5(uuid.NAMESPACE_DNS, "example.org")), +]) +def test_id_property_not_a_valid_hex_uuid(value): with pytest.raises(ValueError) as excinfo: - idprop.clean('my-type--foo') + ID_PROP.clean(value) assert str(excinfo.value) == "must have a valid UUID after the prefix." - assert idprop.clean(idprop.default()) + +def test_id_property_default(): + default = ID_PROP.default() + assert ID_PROP.clean(default) == default @pytest.mark.parametrize("value", [