def post(self, request):  # pylint: disable=no-self-use
        """ receive artifact information, and locate all threats that match it """
        response = None

        def check_required_value(
            arg_name,
            dictionary=request.data,
            description_format='Required parameter "{arg_name}" was not provided'
        ):
            """
            Check that a required value has been provided by the client

            Arguments:
                arg_name - name of the value that should be present
                description_format - format specification of descriptive message
            """
            if arg_name not in dictionary:
                raise ValueError("{} - {}".format(
                    description_format.format(arg_name=arg_name),
                    json.dumps(dictionary),
                ))

        try:
            context_data = request.data
            if request.content_type.startswith('multipart/form-data'):
                check_required_value('artifact')
                context_data = json.loads(request.data['artifact'])
                check_required_value('type', context_data)
                if context_data['type'] == "file.content":
                    check_required_value('file', request.FILES)
                    context_data['value'] = request.FILES['file']
                check_required_value('value', context_data)
            else:
                check_required_value('type')
                check_required_value('value')

            # Generate a search context
            context = SearchContext(context_data)
            matching_threats = search_artifacts(context_data['type'],
                                                context_data['value'],
                                                True,
                                                context=context)
            response = process_threat_results(matching_threats, context)
            context.save()

        except ValueError as ve:
            response = Response({'error': '{}'.format(str(ve))},
                                status.HTTP_400_BAD_REQUEST)

        # Keep broad exception handler, as this is an entry point to the service interface
        except Exception as ex:  # pylint: disable=broad-except
            response = Response({'error': '{}'.format(str(ex))},
                                status.HTTP_500_INTERNAL_SERVER_ERROR)

        return response
Esempio n. 2
0
    def test_regular_context(self):
        context = SearchContext({
            "type": "net.ip",
            "value": "192.168.1.1",
        })
        context.save()

        loaded_context = SearchContext.load(context.id)

        self.assertEqual(context.type, loaded_context.type)
        self.assertEqual(context.value, loaded_context.value)
        self.assertEqual(context.id, loaded_context.id)
Esempio n. 3
0
    def test_file_context(self):
        response = None

        with open("threats/test_data/boss.gif", "rb") as boss_reader:
            file_data = boss_reader.read()
            boss_reader.seek(0)
            response = self.client.post('/', {
                'artifact': '{"type": "file.content"}',
                'file': boss_reader
            },
                                        format="multipart")

        upload_file_args = {
            "name": "boss.gif",
            "content_type": "application/octet-stream",
            "size": 29927,
            "charset": None,
        }

        self.assertEqual(response.status_code, 200)

        temp_file = TemporaryUploadedFile(**upload_file_args)
        temp_file.write(file_data)
        temp_file.flush()

        context = SearchContext({"type": "file.content", "value": temp_file})
        context.save()

        self.assertEqual(context.file_data_len, len(file_data))

        loaded_context = SearchContext.load(context.id)
        self.assertEqual(loaded_context.base64_file_data_len,
                         context.base64_file_data_len)
        self.assertEqual(loaded_context.file_data_len, context.file_data_len)

        with open(loaded_context.value.temporary_file_path(),
                  "rb") as temp_file:
            loaded_file_data = temp_file.read()

        for counter in range(0, len(loaded_file_data) // 100):
            begin = counter * 100
            end = begin + 100
            self.assertEqual(file_data[begin:end], loaded_file_data[begin:end])

        self.assertEqual(len(file_data), len(loaded_file_data))
Esempio n. 4
0
    def test_async_search(self):
        """ test search operation flagged within search context """
        artifact_type = "net.ip"
        artifact_value = "192.168.1.1"
        context = SearchContext({
            "type": artifact_type,
            "value": artifact_value
        })

        hits = search_artifacts(artifact_type,
                                artifact_value,
                                True,
                                context=context)
        self.assertTrue(len(hits) == 0)
        context.save()

        # try again, still should find nothing
        hits = search_artifacts(artifact_type, artifact_value)
        self.assertTrue(len(hits) == 0)
        context = SearchContext.load(context.id)
        self.assertTrue(context.pending_searches)

        TestArtifactSearch.add_result("Test result posted", artifact_type,
                                      artifact_value)
        # now should find something, other search engine should've added something
        hits = search_artifacts(artifact_type, artifact_value)
        self.assertTrue(len(hits) == 1)
        context = SearchContext.load(context.id)
        self.assertTrue(context.pending_searches)

        TestArtifactSearch.search_complete_flag().wait(2)
        context = SearchContext.load(context.id)
        self.assertFalse(context.pending_searches)
Esempio n. 5
0
    def test_2_async_searchers(self):
        """ test adding threat info using dict objects instead of instances """
        artifact_type = "net.ip"
        artifact_value = "192.168.1.1"
        context = SearchContext({
            "type": artifact_type,
            "value": artifact_value
        })

        hits = search_artifacts(artifact_type,
                                artifact_value,
                                True,
                                context=context)
        self.assertTrue(len(hits) == 0)
        context.save()

        # try again, still should find nothing
        hits = search_artifacts(artifact_type, artifact_value)
        self.assertTrue(len(hits) == 0)
        context = SearchContext.load(context.id)
        self.assertTrue(context.pending_searches)

        TestDictArtifactSearch.add_result("Test result posted", artifact_type,
                                          artifact_value)
        hits = search_artifacts(artifact_type, artifact_value)
        self.assertTrue(len(hits) == 1)
        context = SearchContext.load(context.id)
        self.assertTrue(context.pending_searches)

        TestArtifactSearch.add_result("Another test result", artifact_type,
                                      artifact_value)
        hits = search_artifacts(artifact_type, artifact_value)
        self.assertTrue(len(hits) == 2)
        context = SearchContext.load(context.id)
        self.assertTrue(context.pending_searches)

        TestDictArtifactSearch.search_complete_flag().wait(2)
        hits = search_artifacts(artifact_type, artifact_value)
        self.assertTrue(len(hits) == 2)
        context = SearchContext.load(context.id)
        self.assertTrue(context.pending_searches)

        TestArtifactSearch.search_complete_flag().wait(2)
        hits = search_artifacts(artifact_type, artifact_value)
        self.assertTrue(len(hits) == 2)
        context = SearchContext.load(context.id)
        self.assertFalse(context.pending_searches)
Esempio n. 6
0
    def test_results_already_stored(self):
        """ Test duplicate entries from same searcher """
        artifact_type = "net.ip"
        artifact_value = "192.168.1.1"
        context = SearchContext({
            "type": artifact_type,
            "value": artifact_value
        })

        hits = search_artifacts(artifact_type,
                                artifact_value,
                                True,
                                context=context)
        self.assertTrue(len(hits) == 0)
        context.save()

        # try again, still should find nothing
        hits = search_artifacts(artifact_type, artifact_value)
        self.assertTrue(len(hits) == 0)
        context = SearchContext.load(context.id)
        self.assertTrue(context.pending_searches)

        TestArtifactSearch.add_result("Test result posted", artifact_type,
                                      artifact_value)

        # now should find something, other search engine should've added something
        hits = search_artifacts(artifact_type, artifact_value)
        self.assertTrue(len(hits) == 1)

        # add the same result again from the same searcher - should still only get 1 result due to duplicate detection
        TestArtifactSearch.add_result("Test result posted", artifact_type,
                                      artifact_value)
        TestArtifactSearch.search_complete_flag().wait(2)

        # now should find something, other search engine should've added something
        hits = search_artifacts(artifact_type, artifact_value)
        self.assertTrue(len(hits) == 1)
    def get(self, request, request_id):
        """ Fetch results corresponding to given request id """
        request_id = request_id.rstrip('/')
        context = SearchContext.load(request_id)
        if context is None:
            # We return "no content" because we have none
            # 404 will cause the custom threat service caller to stop processing
            return Response({"error": "'{}' was not found".format(request_id)},
                            status.HTTP_204_NO_CONTENT)

        try:
            matching_threats = search_artifacts(context.type, context.value)
            response = process_threat_results(matching_threats, context)

        # Keep broad exception handler, as this is an entry point to the service interface
        except Exception as ex:  # pylint: disable=broad-except
            response = Response({'error': '{}'.format(str(ex))},
                                status.HTTP_500_INTERNAL_SERVER_ERROR)

        return response