def testUserChangesToCopiedFlowAreRespected(self): args = flows_processes.ListProcessesArgs(filename_regex="test[a-z]*", fetch_binaries=True) flow.StartAFF4Flow(flow_name=flows_processes.ListProcesses.__name__, args=args, client_id=self.client_id, output_plugins=[self.email_descriptor], token=self.token) # Navigate to client and select newly created flow. self.Open("/#/clients/C.0000000000000001/flows") self.Click("css=td:contains('ListProcesses')") # Open wizard and change the arguments. self.Click("css=button[name=copy_flow]") self.Type("css=label:contains('Filename Regex') ~ * input", "somethingElse*") self.Click( "css=label:contains('Fetch Binaries') ~ * input[type=checkbox]") # Change output plugin and add another one. self.Click("css=label:contains('Output Plugins') ~ * button") self.Select( "css=grr-output-plugin-descriptor-form " "label:contains('Plugin') ~ * select:eq(0)", "DummyOutputPlugin") self.Type( "css=grr-output-plugin-descriptor-form " "label:contains('Filename Regex'):eq(0) ~ * input:text", "foobar!") self.Click("css=button:contains('Launch')") # Check that flows list got updated and that the new flow is selected. self.WaitUntil( self.IsElementPresent, "css=grr-client-flows-list tr:contains('ListProcesses'):nth(1)") self.WaitUntil( self.IsElementPresent, "css=grr-client-flows-list " "tr:contains('ListProcesses'):nth(0).row-selected") # Now open the last flow and check that it has the changes we made. fd = aff4.FACTORY.Open(self.client_id.Add("flows"), token=self.token) flows = sorted(fd.ListChildren(), key=lambda x: x.age) fobj = aff4.FACTORY.Open(flows[-1], token=self.token) self.assertEqual( fobj.args, flows_processes.ListProcessesArgs( filename_regex="somethingElse*", )) self.assertListEqual(list(fobj.runner_args.output_plugins), [ rdf_output_plugin.OutputPluginDescriptor( plugin_name=gui_test_lib.DummyOutputPlugin.__name__, plugin_args=flows_processes.ListProcessesArgs( filename_regex="foobar!")), self.email_descriptor ])
def testCopyingFlowUpdatesFlowListAndSelectsNewFlow(self): args = flows_processes.ListProcessesArgs(filename_regex="test[a-z]*", fetch_binaries=True) flow.StartAFF4Flow(flow_name=flows_processes.ListProcesses.__name__, args=args, client_id=self.client_id, token=self.token) # Navigate to client and select newly created flow. self.Open("/#/clients/C.0000000000000001/flows") self.Click("css=td:contains('ListProcesses')") # Check that there's only one ListProcesses flow. self.WaitUntilNot( self.IsElementPresent, "css=grr-client-flows-list tr:contains('ListProcesses'):nth(1)") # Open wizard and check if flow arguments are copied. self.Click("css=button[name=copy_flow]") self.Click("css=button:contains('Launch'):not([disabled])") # Check that flows list got updated and that the new flow is selected. self.WaitUntil( self.IsElementPresent, "css=grr-client-flows-list tr:contains('ListProcesses'):nth(1)") self.WaitUntil( self.IsElementPresent, "css=grr-client-flows-list " "tr:contains('ListProcesses'):nth(0).row-selected")
def testOriginalFlowArgsAreShownInCopyForm(self): args = flows_processes.ListProcessesArgs(filename_regex="test[a-z]*", fetch_binaries=True) flow.StartAFF4Flow(flow_name=flows_processes.ListProcesses.__name__, args=args, client_id=self.client_id, output_plugins=[self.email_descriptor], token=self.token) # Navigate to client and select newly created flow. self.Open("/#/clients/C.0000000000000001/flows") self.Click("css=td:contains('ListProcesses')") # Open wizard and check if flow arguments are copied. self.Click("css=button[name=copy_flow]") self.WaitUntil(self.IsTextPresent, "Copy ListProcesses flow") self.WaitUntilEqual("test[a-z]*", self.GetValue, "css=label:contains('Filename Regex') ~ * input") self.WaitUntil( self.IsChecked, "css=label:contains('Fetch Binaries') " "~ * input[type=checkbox]") # Check that output plugin info is also copied. self.WaitUntilEqual("string:EmailOutputPlugin", self.GetValue, "css=label:contains('Plugin') ~ * select") self.WaitUntilEqual("test@localhost", self.GetValue, "css=label:contains('Email address') ~ * input") self.WaitUntilEqual("42", self.GetValue, "css=label:contains('Emails limit') ~ * input")
def testCreateFlowFromClientRef(self): client_urn = self.SetupClient(0) args = processes.ListProcessesArgs(filename_regex="blah", fetch_binaries=True) if data_store.RelationalDBFlowsEnabled(): flows = data_store.REL_DB.ReadAllFlowObjects(client_urn.Basename()) self.assertEmpty(flows) else: children = aff4.FACTORY.Open(client_urn, token=self.token).ListChildren() self.assertEmpty(list(children)) client_ref = self.api.Client(client_id=client_urn.Basename()) result_flow = client_ref.CreateFlow( name=processes.ListProcesses.__name__, args=args.AsPrimitiveProto()) if data_store.RelationalDBFlowsEnabled(): flows = data_store.REL_DB.ReadAllFlowObjects(client_urn.Basename()) self.assertLen(flows, 1) self.assertEqual(flows[0].args, args) else: children = aff4.FACTORY.Open(client_urn, token=self.token).ListChildren() self.assertLen(list(children), 1) result_flow_obj = aff4.FACTORY.Open(result_flow.data.urn, token=self.token) self.assertEqual(result_flow_obj.args, args)
def Run(self): client_urn = self.SetupClient(0) client_id = client_urn.Basename() def ReplaceFlowId(): if data_store.RelationalDBFlowsEnabled(): flows = data_store.REL_DB.ReadAllFlowObjects( client_id=client_id) self.assertNotEmpty(flows) flow_id = flows[0].flow_id else: flows_dir_fd = aff4.FACTORY.Open(client_urn.Add("flows"), token=self.token) flow_id = list(flows_dir_fd.ListChildren())[0].Basename() return api_regression_test_lib.GetFlowTestReplaceDict( client_id, flow_id) with test_lib.FakeTime(42): self.Check("CreateFlow", args=flow_plugin.ApiCreateFlowArgs( client_id=client_id, flow=flow_plugin.ApiFlow( name=processes.ListProcesses.__name__, args=processes.ListProcessesArgs( filename_regex=".", fetch_binaries=True), runner_args=rdf_flow_runner.FlowRunnerArgs( output_plugins=[], notify_to_user=True))), replace=ReplaceFlowId)
def testPidFiltering(self): client_id = self.SetupClient(0) proc_foo = rdf_client.Process() proc_foo.pid = 42 proc_foo.exe = "/usr/bin/foo" proc_bar = rdf_client.Process() proc_bar.pid = 108 proc_bar.exe = "/usr/bin/bar" proc_baz = rdf_client.Process() proc_baz.pid = 1337 proc_baz.exe = "/usr/bin/baz" args = flow_processes.ListProcessesArgs() args.pids = [42, 1337] client_mock = action_mocks.ListProcessesMock([proc_foo, proc_bar, proc_baz]) flow_id = flow_test_lib.StartAndRunFlow( flow_processes.ListProcesses, client_mock=client_mock, client_id=client_id, flow_args=args, ) results = flow_test_lib.GetFlowResults(client_id=client_id, flow_id=flow_id) self.assertLen(results, 2) result_exes = {result.exe for result in results} self.assertIn("/usr/bin/foo", result_exes) self.assertIn("/usr/bin/baz", result_exes) self.assertNotIn("/usr/bin/bar", result_exes)
def testPostMethodWorks(self): client_id = self.SetupClient(0) args = processes.ListProcessesArgs( filename_regex="blah", fetch_binaries=True) client_ref = self.api.Client(client_id=client_id) result_flow = client_ref.CreateFlow( name=processes.ListProcesses.__name__, args=args.AsPrimitiveProto()) self.assertTrue(result_flow.client_id)
def testHuntIsStoppedIfAveragePerClientResultsCountTooHigh(self): with utils.Stubber(implementation.GRRHunt, "MIN_CLIENTS_FOR_AVERAGE_THRESHOLDS", 4): flow_args = processes.ListProcessesArgs() flow_runner_args = rdf_flow_runner.FlowRunnerArgs( flow_name=processes.ListProcesses.__name__) hunt_urn = self.StartHunt( flow_args=flow_args, flow_runner_args=flow_runner_args, avg_results_per_client_limit=1, token=self.token) def RunOnClients(client_ids, num_processes): client_mock = action_mocks.ListProcessesMock( [rdf_client.Process(pid=1, exe="a.exe")] * num_processes) self.AssignTasksToClients(client_ids) hunt_test_lib.TestHuntHelper( client_mock, client_ids, check_flow_errors=False, token=self.token) def CheckState(expected_state, expected_results_count): hunt_obj = aff4.FACTORY.Open(hunt_urn, token=self.token) self.assertEqual(hunt_obj.Get(hunt_obj.Schema.STATE), expected_state) self.assertEqual(hunt_obj.context.results_count, expected_results_count) RunOnClients(self.client_ids[:2], 1) # Hunt should still be running: we got 1 response from 2 clients. We need # at least 3 clients to start calculating the average. CheckState("STARTED", 2) RunOnClients([self.client_ids[2]], 2) # Hunt should still be running: we got 1 response for first 2 clients and # 2 responses for the third. This is over the limit but we need at least 4 # clients to start applying thresholds. CheckState("STARTED", 4) RunOnClients([self.client_ids[3]], 0) # Hunt should still be running: we got 1 response for first 2 clients, # 2 responses for the third and zero for the 4th. This makes it 1 result # per client on average. This is within the limit of 1. CheckState("STARTED", 4) RunOnClients(self.client_ids[4:5], 2) # Hunt should be terminated: 5 clients did run and we got 6 results. # That's more than the allowed average of 1. # Note that this check also implicitly checks that the 6th client didn't # run at all (otherwise total number of results would be 8, not 6). CheckState("STOPPED", 6) self._CheckHuntStoppedNotification( "reached the average results per client")
def testCreateFlowWithUnicodeArguments(self): unicode_str = "🐊 🐢 🦎 🐍" client_id = self.SetupClient(0) args = processes.ListProcessesArgs( filename_regex=unicode_str, fetch_binaries=True) client_ref = self.api.Client(client_id=client_id) result_flow = client_ref.CreateFlow( name=processes.ListProcesses.__name__, args=args.AsPrimitiveProto()) got_flow = client_ref.Flow(flow_id=result_flow.flow_id).Get() self.assertEqual(got_flow.args.filename_regex, unicode_str)
def testApprovalIndicatesThatHuntWasCopiedFromFlow(self): email_descriptor = rdf_output_plugin.OutputPluginDescriptor( plugin_name=compatibility.GetName(email_plugin.EmailOutputPlugin), plugin_args=email_plugin.EmailOutputPluginArgs( email_address="test@localhost", emails_limit=42)) args = flows_processes.ListProcessesArgs( filename_regex="test[a-z]*", fetch_binaries=True) flow_test_lib.StartFlow( flows_processes.ListProcesses, flow_args=args, client_id=self.client_id, output_plugins=[email_descriptor]) self.Open("/#/clients/%s" % self.client_id) self.Click("css=a[grrtarget='client.flows']") self.Click("css=td:contains('ListProcesses')") # Open the wizard. self.Click("css=button[name=create_hunt]") # Go to the hunt parameters page. self.Click("css=grr-new-hunt-wizard-form button.Next") # Go to the output plugins page. self.Click("css=grr-new-hunt-wizard-form button.Next") # Go to the rules page. self.Click("css=grr-new-hunt-wizard-form button.Next") # Go to the review page. self.Click("css=grr-new-hunt-wizard-form button.Next") # Create the hunt. self.Click("css=button:contains('Create Hunt')") self.Click("css=button:contains('Done')") # Request an approval. hunts = data_store.REL_DB.ListHuntObjects(offset=0, count=1) h = hunts[0] approval_id = self.RequestHuntApproval( h.hunt_id, requestor=self.token.username, reason="reason", approver=self.token.username) # Open the approval page. self.Open("/#/users/%s/approvals/hunt/%s/%s" % (self.token.username, h.hunt_id, approval_id)) self.WaitUntil(self.IsElementPresent, "css=div.panel-body:contains('This hunt was created from')")
def testCreateFlowFromClientRef(self): client_id = self.SetupClient(0) args = processes.ListProcessesArgs( filename_regex="blah", fetch_binaries=True) flows = data_store.REL_DB.ReadAllFlowObjects(client_id) self.assertEmpty(flows) client_ref = self.api.Client(client_id=client_id) client_ref.CreateFlow( name=processes.ListProcesses.__name__, args=args.AsPrimitiveProto()) flows = data_store.REL_DB.ReadAllFlowObjects(client_id) self.assertLen(flows, 1) self.assertEqual(flows[0].args, args)
def testCreateFlowFromClientObject(self): client_urn = self.SetupClient(0) args = processes.ListProcessesArgs( filename_regex="blah", fetch_binaries=True) children = aff4.FACTORY.Open(client_urn, token=self.token).ListChildren() self.assertEmpty(list(children)) client = self.api.Client(client_id=client_urn.Basename()).Get() result_flow = client.CreateFlow( name=processes.ListProcesses.__name__, args=args.AsPrimitiveProto()) children = aff4.FACTORY.Open(client_urn, token=self.token).ListChildren() self.assertLen(list(children), 1) result_flow_obj = aff4.FACTORY.Open(result_flow.data.urn, token=self.token) self.assertEqual(result_flow_obj.args, args)
def testAddingOutputPluginToCopiedFlowWorks(self): args = flows_processes.ListProcessesArgs( filename_regex="test[a-z]*", fetch_binaries=True) flow_test_lib.StartFlow( flows_processes.ListProcesses, flow_args=args, client_id=self.client_id) # Navigate to client and select newly created flow. self.Open("/#/clients/C.0000000000000001/flows") self.Click("css=td:contains('ListProcesses')") # Open wizard and check if flow arguments are copied. self.Click("css=button[name=copy_flow]") self.Click("css=label:contains('Output Plugins') ~ * button") self.WaitUntil(self.IsElementPresent, "css=label:contains('Plugin') ~ * select")
def Run(self): client_id = self.SetupClient(0) def ReplaceFlowId(): flows_dir_fd = aff4.FACTORY.Open(client_id.Add("flows"), token=self.token) flow_urn = list(flows_dir_fd.ListChildren())[0] return {flow_urn.Basename(): "W:ABCDEF"} with test_lib.FakeTime(42): self.Check("CreateFlow", args=flow_plugin.ApiCreateFlowArgs( client_id=client_id.Basename(), flow=flow_plugin.ApiFlow( name=processes.ListProcesses.__name__, args=processes.ListProcessesArgs( filename_regex=".", fetch_binaries=True), runner_args=rdf_flow_runner.FlowRunnerArgs( output_plugins=[], notify_to_user=False))), replace=ReplaceFlowId)
def Run(self): client_id = self.SetupClient(0) def ReplaceFlowId(): flows = data_store.REL_DB.ReadAllFlowObjects(client_id=client_id) self.assertNotEmpty(flows) flow_id = flows[0].flow_id return api_regression_test_lib.GetFlowTestReplaceDict(client_id, flow_id) with test_lib.FakeTime(42): self.Check( "CreateFlow", args=flow_plugin.ApiCreateFlowArgs( client_id=client_id, flow=flow_plugin.ApiFlow( name=processes.ListProcesses.__name__, args=processes.ListProcessesArgs( filename_regex=".", fetch_binaries=True), runner_args=rdf_flow_runner.FlowRunnerArgs( output_plugins=[], notify_to_user=True))), replace=ReplaceFlowId)
def testCreateHuntFromFlow(self): email_descriptor = rdf_output_plugin.OutputPluginDescriptor( plugin_name=compatibility.GetName(email_plugin.EmailOutputPlugin), plugin_args=email_plugin.EmailOutputPluginArgs( email_address="test@localhost", emails_limit=42)) args = flows_processes.ListProcessesArgs( filename_regex="test[a-z]*", fetch_binaries=True) flow_test_lib.StartFlow( flows_processes.ListProcesses, flow_args=args, client_id=self.client_id, output_plugins=[email_descriptor]) # Navigate to client and select newly created flow. self.Open("/#/clients/%s" % self.client_id) self.Click("css=a[grrtarget='client.flows']") self.Click("css=td:contains('ListProcesses')") # Open wizard and check if flow arguments are copied. self.Click("css=button[name=create_hunt]") self.WaitUntilEqual("test[a-z]*", self.GetValue, "css=label:contains('Filepath Regex') ~ * input") self.WaitUntil( self.IsChecked, "css=label:contains('Fetch Binaries') " "~ * input[type=checkbox]") # Go to output plugins page and check that we did not copy the output # plugins. self.Click("css=button:contains('Next')") self.WaitUntil(self.IsElementPresent, "css=grr-wizard-form:contains('Hunt parameters')") self.Click("css=grr-new-hunt-wizard-form button.Next") self.WaitUntil(self.IsElementPresent, "css=grr-wizard-form:contains('How to process results')") self.WaitUntilNot(self.IsElementPresent, "css=grr-output-plugin-descriptor-form") # Nothing else to check, so finish the hunt. # Click on "Next" button self.Click("css=grr-new-hunt-wizard-form button.Next") self.WaitUntil(self.IsElementPresent, "css=grr-wizard-form:contains('Where to run?')") self.Click("css=button:contains('Next')") self.WaitUntil(self.IsElementPresent, "css=grr-wizard-form:contains('Review')") self.Click("css=button:contains('Create Hunt')") self.Click("css=button:contains('Done')") # Check that we get redirected to ManageHunts. self.WaitUntilEqual(1, self.GetCssCount, "css=grr-hunts-list table tbody tr") self.WaitUntilEqual(1, self.GetCssCount, "css=grr-hunts-list table tbody tr.row-selected") self.WaitUntil(self.IsTextPresent, "GenericHunt") self.WaitUntil(self.IsTextPresent, compatibility.GetName(flows_processes.ListProcesses))