Exemplo n.º 1
0
  def ExpireRules(self):
    """Removes any rules with an expiration date in the past."""
    rules = self.Get(self.Schema.RULES)
    new_rules = self.Schema.RULES()
    now = time.time() * 1e6
    expired_session_ids = set()

    for rule in rules:
      if rule.expires > now:
        new_rules.Append(rule)
      else:
        for action in rule.actions:
          if action.hunt_id:
            expired_session_ids.add(action.hunt_id)

    if expired_session_ids:
      with data_store.DB.GetMutationPool() as pool:
        # Notify the worker to mark this hunt as terminated.
        manager = queue_manager.QueueManager(token=self.token)
        manager.MultiNotifyQueue([
            rdf_flows.GrrNotification(session_id=session_id)
            for session_id in expired_session_ids
        ],
                                 mutation_pool=pool)

    if len(new_rules) < len(rules):
      self.Set(self.Schema.RULES, new_rules)
      self.Flush()
Exemplo n.º 2
0
    def CheckNotificationsDisappear(self, session_id):
        worker_obj = self._TestWorker()
        manager = queue_manager.QueueManager(token=self.token)
        notification = rdf_flows.GrrNotification(session_id=session_id)
        with data_store.DB.GetMutationPool() as pool:
            manager.NotifyQueue(notification, mutation_pool=pool)

        notifications = manager.GetNotifications(queues.FLOWS)

        # Check the notification is there. With multiple worker queue shards we can
        # get other notifications such as for audit event listeners, so we need to
        # filter out ours.
        notifications = [
            x for x in notifications if x.session_id == session_id
        ]
        self.assertLen(notifications, 1)

        # Process all messages
        worker_obj.RunOnce()
        worker_obj.thread_pool.Join()

        notifications = manager.GetNotifications(queues.FLOWS)
        notifications = [
            x for x in notifications if x.session_id == session_id
        ]

        # Check the notification is now gone.
        self.assertEmpty(notifications)
Exemplo n.º 3
0
  def testAuthentication2(self):
    """Test that flows refuse to processes unauthenticated messages.

    Here we try to simulate an attacker injecting unauthenticated
    messages midstream.

    The current implementation actually fails to process the entire
    flow since the injected messages displace the real ones if they
    arrive earlier. This can be an effective DoS against legitimate
    clients but would require attackers to guess session ids.
    """
    flow_obj = self.FlowSetup(flow_test_lib.FlowOrderTest.__name__)

    # Simulate processing messages arriving in random order
    message_ids = [1, 2]
    self.SendMessages(message_ids, flow_obj.session_id, authenticated=True)

    # Now suppose some of the messages are spoofed
    message_ids = [3, 4, 5]
    self.SendMessages(message_ids, flow_obj.session_id, authenticated=False)

    # And now our real messages arrive
    message_ids = [5, 6]
    self.SendMessages(message_ids, flow_obj.session_id, authenticated=True)

    # Send the status message
    self.SendOKStatus(7, flow_obj.session_id)

    runner = flow_obj.GetRunner()
    notification = rdf_flows.GrrNotification(
        timestamp=rdfvalue.RDFDatetime.Now())
    runner.ProcessCompletedRequests(notification)

    # Some messages should actually be processed
    self.assertEqual(flow_obj.messages, [1, 2, 5, 6])
Exemplo n.º 4
0
    def QueueNotification(self, notification=None, timestamp=None, **kw):
        """Queues a notification for a flow."""

        if notification is None:
            notification = rdf_flows.GrrNotification(**kw)

        session_id = notification.session_id

        if session_id:
            if timestamp is None:
                timestamp = self.frozen_timestamp

            notification.timestamp = timestamp

            # We must not store more than one notification per session id and
            # timestamp or there will be race conditions. We therefore only keep
            # the one with the highest request number (indicated by last_status).
            # Note that timestamp might be None. In that case we also only want
            # to keep the latest.
            if timestamp is None:
                ts_str = "None"
            else:
                ts_str = int(timestamp)
            key = "%s!%s" % (session_id, ts_str)
            existing = self.notifications.get(key)
            if existing is not None:
                if existing.last_status < notification.last_status:
                    self.notifications[key] = notification
            else:
                self.notifications[key] = notification
Exemplo n.º 5
0
    def testNotificationReschedulingTTL(self):
        """Test that notifications are not rescheduled forever."""

        with test_lib.FakeTime(10000):
            worker_obj = self._TestWorker()
            flow_obj = self.FlowSetup("RaisingTestFlow")
            session_id = flow_obj.session_id
            flow_obj.Close()

            with queue_manager.QueueManager(token=self.token) as manager:
                notification = rdf_flows.GrrNotification(session_id=session_id,
                                                         timestamp=time.time(),
                                                         last_status=1)
                with data_store.DB.GetMutationPool() as pool:
                    manager.NotifyQueue(notification, mutation_pool=pool)

                notifications = manager.GetNotifications(queues.FLOWS)
                # Check the notification is there.
                notifications = [
                    n for n in notifications if n.session_id == session_id
                ]
                self.assertLen(notifications, 1)

        delay = flow_runner.FlowRunner.notification_retry_interval

        ttl = notification.ttl
        for i in range(ttl - 1):
            with test_lib.FakeTime(10000 + 100 + delay * (i + 1)):
                # Process all messages.
                worker_obj.RunOnce()
                worker_obj.thread_pool.Join()

                notifications = manager.GetNotifications(queues.FLOWS)
                # Check the notification is for the correct session_id.
                notifications = [
                    n for n in notifications if n.session_id == session_id
                ]
                self.assertLen(notifications, 1)

        with test_lib.FakeTime(10000 + 100 + delay * ttl):
            # Process all messages.
            worker_obj.RunOnce()
            worker_obj.thread_pool.Join()

            notifications = manager.GetNotifications(queues.FLOWS)
            self.assertEmpty(notifications)
Exemplo n.º 6
0
    def testReordering(self):
        """Check that out of order client messages are reordered."""
        flow_obj = self.FlowSetup(flow_test_lib.FlowOrderTest.__name__)

        # Simulate processing messages arriving in random order
        message_ids = [2, 1, 4, 3, 5]
        self.SendMessages(message_ids, flow_obj.session_id)

        # Send the status message
        self.SendOKStatus(6, flow_obj.session_id)

        runner = flow_obj.GetRunner()
        notification = rdf_flows.GrrNotification(
            timestamp=rdfvalue.RDFDatetime.Now())
        runner.ProcessCompletedRequests(notification)

        # Check that the messages were processed in order
        self.assertEqual(flow_obj.messages, [1, 2, 3, 4, 5])
Exemplo n.º 7
0
  def testAuthentication1(self):
    """Test that flows refuse to processes unauthenticated messages."""
    flow_obj = self.FlowSetup(flow_test_lib.FlowOrderTest.__name__)

    # Simulate processing messages arriving in random order
    message_ids = [2, 1, 4, 3, 5]
    self.SendMessages(message_ids, flow_obj.session_id, authenticated=False)

    # Send the status message
    self.SendOKStatus(6, flow_obj.session_id)

    runner = flow_obj.GetRunner()
    notification = rdf_flows.GrrNotification(
        timestamp=rdfvalue.RDFDatetime.Now())
    runner.ProcessCompletedRequests(notification)

    # Now messages should actually be processed
    self.assertEqual(flow_obj.messages, [])
Exemplo n.º 8
0
    def testNotificationRacesAreResolved(self):
        # We need a random flow object for this test.
        session_id = flow.StartAFF4Flow(client_id=self.client_id,
                                        flow_name="WorkerSendingTestFlow",
                                        token=self.token)
        worker_obj = self._TestWorker()
        manager = queue_manager.QueueManager(token=self.token)
        manager.DeleteNotification(session_id)
        manager.Flush()

        # We simulate a race condition here - the notification for request #1 is
        # there but the actual request #1 is not. The worker should pick up the
        # notification, notice that the request #1 is not there yet and reschedule
        # the notification.
        notification = rdf_flows.GrrNotification(session_id=session_id,
                                                 last_status=1)
        with data_store.DB.GetMutationPool() as pool:
            manager.NotifyQueue(notification, mutation_pool=pool)

        notifications = manager.GetNotifications(queues.FLOWS)
        # Check the notification is there.
        notifications = [
            n for n in notifications if n.session_id == session_id
        ]
        self.assertLen(notifications, 1)

        # Process all messages
        worker_obj.RunOnce()
        worker_obj.thread_pool.Join()

        delay = flow_runner.FlowRunner.notification_retry_interval
        with test_lib.FakeTime(time.time() + 10 + delay):
            requeued_notifications = manager.GetNotifications(queues.FLOWS)
            # Check that there is a new notification.
            notifications = [
                n for n in notifications if n.session_id == session_id
            ]
            self.assertLen(requeued_notifications, 1)

            self.assertEqual(requeued_notifications[0].first_queued,
                             notifications[0].first_queued)
            self.assertNotEqual(requeued_notifications[0].timestamp,
                                notifications[0].timestamp)