Repository: oasis-open/cti-taxii-server

Issue:
BUG: checking new object IDs as existing already always fail
https://github.com/oasis-open/cti-taxii-server/blob/f6398926d866989201e754dca0fec1e1a041acdf/medallion/backends/memory_backend.py#L166

This line will always fail, you're checking that the ID of the object belongs in the array of objects instead of checking if the ID of the object exists as the ID of _any_ of the objects

Discussion:

Patch:
diff --git a/medallion/backends/memory_backend.py b/medallion/backends/memory_backend.py
index 8da67b0..b07ae14 100644
--- a/medallion/backends/memory_backend.py
+++ b/medallion/backends/memory_backend.py
@@ -163,22 +163,23 @@ class MemoryBackend(Backend):
                     try:
                         for new_obj in objs["objects"]:
                             id_and_version_already_present = False
-                            if new_obj["id"] in collection["objects"]:
-                                current_obj = collection["objects"][new_obj["id"]]
-                                if "modified" in new_obj:
-                                    if new_obj["modified"] == current_obj["modified"]:
+                            for obj in collection["objects"]:
+                                id_and_version_already_present = False
+
+                                if new_obj['id'] == obj['id']:
+                                    if "modified" in new_obj:
+                                        if new_obj["modified"] == obj["modified"]:
+                                            id_and_version_already_present = True
+                                    else:
+                                        # There is no modified field, so this object is immutable
                                         id_and_version_already_present = True
-                                else:
-                                    # There is no modified field, so this object is immutable
-                                    id_and_version_already_present = True
                             if not id_and_version_already_present:
                                 collection["objects"].append(new_obj)
                                 self._update_manifest(new_obj, api_root, collection["id"])
                                 successes.append(new_obj["id"])
                                 succeeded += 1
                             else:
-                                failures.append({"id": new_obj["id"],
-                                                 "message": "Unable to process object"})
+                                failures.append({"id": new_obj["id"], "message": "Unable to process object"})
                                 failed += 1
                     except Exception as e:
                         raise ProcessingError("While processing supplied content, an error occured", e)


Test patch:
diff --git a/medallion/test/test_memory_backend.py b/medallion/test/test_memory_backend.py
index a23b9f1..7c9f982 100644
--- a/medallion/test/test_memory_backend.py
+++ b/medallion/test/test_memory_backend.py
@@ -207,6 +207,54 @@ class TestTAXIIServerWithMemoryBackend(unittest.TestCase):
         assert manifests["objects"][0]["id"] == new_id
         # ------------- BEGIN: end manifest section ------------- #
 
+    def test_add_existing_objects(self):
+        new_bundle = copy.deepcopy(API_OBJECTS_2)
+        new_id = "indicator--%s" % uuid.uuid4()
+        new_bundle["objects"][0]["id"] = new_id
+
+        # ------------- BEGIN: add object section ------------- #
+
+        post_header = copy.deepcopy(self.auth)
+        post_header["Content-Type"] = MEDIA_TYPE_STIX_V20
+        post_header["Accept"] = MEDIA_TYPE_TAXII_V20
+
+        r_post = self.client.post(
+            test.ADD_OBJECTS_EP,
+            data=json.dumps(new_bundle),
+            headers=post_header
+        )
+        self.assertEqual(r_post.status_code, 202)
+        self.assertEqual(r_post.content_type, MEDIA_TYPE_TAXII_V20)
+
+        # ------------- END: add object section ------------- #
+        # ------------- BEGIN: add object again section ------------- #
+
+        r_post = self.client.post(
+            test.ADD_OBJECTS_EP,
+            data=json.dumps(new_bundle),
+            headers=post_header
+        )
+        status_response2 = self.load_json_response(r_post.data)
+        self.assertEqual(r_post.status_code, 202)
+        self.assertEqual(status_response2["success_count"], 0)
+        self.assertEqual(status_response2["failures"][0]["message"],
+                         "Unable to process object")
+
+        # ------------- END: add object again section ------------- #
+        # ------------- BEGIN: get object section ------------- #
+
+        get_header = copy.deepcopy(self.auth)
+        get_header["Accept"] = MEDIA_TYPE_STIX_V20
+
+        r_get = self.client.get(
+            test.GET_OBJECTS_EP + "?match[id]=%s" % new_id,
+            headers=get_header
+        )
+        self.assertEqual(r_get.status_code, 200)
+        objs = self.load_json_response(r_get.data)
+        self.assertEqual(len(objs["objects"]), 1)
+        self.assertEqual(objs["objects"][0]["id"], new_id)
+
     def test_client_object_versioning(self):
         new_id = "indicator--%s" % uuid.uuid4()
         new_bundle = copy.deepcopy(API_OBJECTS_2)