def testReordering(self): """Check that out of order client messages are reordered.""" flow_obj = self.FlowSetup("FlowOrderTest") # Simultate 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 message = self.SendOKStatus(6, flow_obj.session_id) runner = flow_runner.FlowRunner(flow_obj) notification = rdfvalue.Notification(timestamp=rdfvalue.RDFDatetime().Now()) runner.ProcessCompletedRequests(notification, [message]) # Check that the messages were processed in order self.assertEqual(flow_obj.messages, [1, 2, 3, 4, 5])
def testAuthentication1(self): """Test that flows refuse to processes unauthenticated messages.""" flow_obj = self.FlowSetup("FlowOrderTest") # Simultate 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 message = self.SendOKStatus(6, flow_obj.session_id) runner = flow_runner.FlowRunner(flow_obj) notification = rdfvalue.Notification(timestamp=rdfvalue.RDFDatetime().Now()) runner.ProcessCompletedRequests(notification, [message]) # Now messages should actually be processed self.assertEqual(flow_obj.messages, [])
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("FlowOrderTest") # Simultate 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 message = self.SendOKStatus(7, flow_obj.session_id) runner = flow_runner.FlowRunner(flow_obj) notification = rdfvalue.Notification(timestamp=rdfvalue.RDFDatetime().Now()) runner.ProcessCompletedRequests(notification, [message]) # Some messages should actually be processed self.assertEqual(flow_obj.messages, [1, 2, 5, 6])
def Notify(self, message_type, subject, msg): """Send a notification to the originating user. Args: message_type: The type of the message. This allows the UI to format a link to the original object e.g. "ViewObject" or "HostInformation" subject: The urn of the AFF4 object of interest in this link. msg: A free form textual message. """ user = self.context.creator # Don't send notifications to system users. if self.args.notify_to_user and user not in aff4.GRRUser.SYSTEM_USERS: # Prefix the message with the hostname of the client we are running # against. if self.args.client_id: client_fd = aff4.FACTORY.Open(self.args.client_id, mode="rw", token=self.token) hostname = client_fd.Get(client_fd.Schema.HOSTNAME) or "" client_msg = "%s: %s" % (hostname, msg) else: client_msg = msg # Add notification to the User object. fd = aff4.FACTORY.Create(aff4.ROOT_URN.Add("users").Add(user), "GRRUser", mode="rw", token=self.token) # Queue notifications to the user. fd.Notify(message_type, subject, client_msg, self.session_id) fd.Close() # Add notifications to the flow. notification = rdfvalue.Notification( type=message_type, subject=utils.SmartUnicode(subject), message=utils.SmartUnicode(msg), source=self.session_id, timestamp=rdfvalue.RDFDatetime().Now()) data_store.DB.Set(self.session_id, aff4.AFF4Object.GRRFlow.SchemaCls.NOTIFICATION, notification, replace=False, sync=False, token=self.token) # Disable further notifications. self.context.user_notified = True # Allow the flow to either specify an event name or an event handler URN. notification_event = (self.args.notification_event or self.args.notification_urn) if notification_event: if self.context.state == rdfvalue.Flow.State.ERROR: status = rdfvalue.FlowNotification.Status.ERROR else: status = rdfvalue.FlowNotification.Status.OK event = rdfvalue.FlowNotification( session_id=self.context.session_id, flow_name=self.args.flow_name, client_id=self.args.client_id, status=status) self.flow_obj.Publish(notification_event, message=event)