def ApprovalCreateRaw(aff4_path, reason="", expire_in=60 * 60 * 24 * 7, token=None, approval_type="ClientApproval"): """Creates an approval with raw access. This method requires raw datastore access to manipulate approvals directly. This currently doesn't work for hunt or cron approvals, because they check that each approver has the admin label. Since the fake users don't exist the check fails. Args: aff4_path: The aff4_path or client id the approval should be created for. reason: The reason to put in the token. expire_in: Expiry in seconds to use in the token. token: The token that will be used. If this is specified reason and expiry are ignored. approval_type: The type of the approval to create. Returns: The token. Raises: RuntimeError: On bad token. """ if approval_type in ["ClientApproval", security.ClientApproval]: urn = rdf_client.ClientURN(aff4_path) else: urn = rdfvalue.RDFURN(aff4_path) if not token: expiry = time.time() + expire_in token = access_control.ACLToken(reason=reason, expiry=expiry) if not token.reason: raise RuntimeError("Cannot create approval with empty reason") if not token.username: token.username = getpass.getuser() approval_urn = security.ApprovalRequestor.ApprovalUrnBuilder( urn.Path(), token.username, token.reason) super_token = access_control.ACLToken(username="******") super_token.supervisor = True if isinstance(approval_type, basestring): approval_type_cls = aff4.AFF4Object.classes[approval_type] else: approval_type_cls = approval_type approval_request = aff4.FACTORY.Create(approval_urn, approval_type_cls, mode="rw", token=super_token) # Add approvals indicating they were approved by fake "raw" mode users. approval_request.AddAttribute( approval_request.Schema.APPROVER("%s1-raw" % token.username)) approval_request.AddAttribute( approval_request.Schema.APPROVER("%s-raw2" % token.username)) approval_request.Close()
def testWhenAuthMgrActiveChecksApproversForEachClientLabel(self, mock_mgr): data_store.REL_DB.AddClientLabels(self.client.client_id, "GRR", ["foo", "bar"]) approval_request = self._CreateRequest(grants=[ rdf_objects.ApprovalGrant(grantor_username="******"), rdf_objects.ApprovalGrant(grantor_username="******") ]) # Make sure approval manager is active. mock_mgr.IsActive.return_value = True approval_checks.CheckApprovalRequest(approval_request) self.assertEqual(len(mock_mgr.CheckApproversForLabel.mock_calls), 2) args = mock_mgr.CheckApproversForLabel.mock_calls[0][1] self.assertEqual(args, (access_control.ACLToken(username="******"), rdfvalue.RDFURN(self.client.client_id), "requestor", set(["grantor1", "grantor2"]), "bar")) args = mock_mgr.CheckApproversForLabel.mock_calls[1][1] self.assertEqual(args, (access_control.ACLToken(username="******"), rdfvalue.RDFURN(self.client.client_id), "requestor", set(["grantor1", "grantor2"]), "foo"))
def testRaisesIfUsernameSetInRequest(self): user = user_plugin.ApiGrrUser(username="******") with self.assertRaises(ValueError): self.handler.Handle(user, token=access_control.ACLToken(username="******")) user = user_plugin.ApiGrrUser(username="******") with self.assertRaises(ValueError): self.handler.Handle(user, token=access_control.ACLToken(username="******"))
def testRendersTraitsPassedInConstructor(self): result = self.handler.Handle( None, token=access_control.ACLToken(username="******")) self.assertFalse(result.interface_traits.create_hunt_action_enabled) handler = user_plugin.ApiGetOwnGrrUserHandler( interface_traits=user_plugin.ApiGrrUserInterfaceTraits( create_hunt_action_enabled=True)) result = handler.Handle(None, token=access_control.ACLToken(username="******")) self.assertTrue(result.interface_traits.create_hunt_action_enabled)
def RequestCronJobApproval(self, cron_job_id, requestor=None, reason=None, email_cc_address=None, approver="approver"): """Request cron job approval for a given cron job.""" if not requestor: requestor = self.token.username if not reason: reason = self.token.reason self.CreateUser(requestor) self.CreateUser(approver) args = api_user.ApiCreateCronJobApprovalArgs( cron_job_id=cron_job_id, approval=api_user.ApiCronJobApproval( reason=reason, notified_users=[approver], email_cc_addresses=([email_cc_address] if email_cc_address else []))) handler = api_user.ApiCreateCronJobApprovalHandler() result = handler.Handle( args, token=access_control.ACLToken(username=requestor)) return result.id
def main(argv=None): del argv # Unused. config.CONFIG.AddContext(contexts.COMMAND_LINE_CONTEXT) config.CONFIG.AddContext( contexts.CONSOLE_CONTEXT, "Context applied when running the console binary.") server_startup.Init() fleetspeak_connector.Init() username = flags.FLAGS.username if not username: username = os.environ["USER"] if not username: print( "Username has to be specified with either --username flag or " "USER environment variable.") sys.exit(1) grrapi = api.GrrApi(connector=api_shell_raw_access_lib.RawConnector( token=access_control.ACLToken(username=username), page_size=flags.FLAGS.page_size)) if flags.FLAGS.exec_code and flags.FLAGS.exec_file: print "--exec_code --exec_file flags can't be supplied together." sys.exit(1) elif flags.FLAGS.exec_code: # pylint: disable=exec-used exec(flags.FLAGS.exec_code, dict(grrapi=grrapi)) # pylint: enable=exec-used elif flags.FLAGS.exec_file: execfile(flags.FLAGS.exec_file, dict(grrapi=grrapi)) else: api_shell_lib.IPShell([sys.argv[0]], user_ns=dict(grrapi=grrapi))
def RequestClientApproval(self, client_id, reason=None, requestor=None, email_cc_address=None, approver="approver"): """Create an approval request to be sent to approver.""" if hasattr(client_id, "Basename"): client_id = client_id.Basename() if not requestor: requestor = self.token.username if not reason: reason = self.token.reason self.CreateUser(requestor) self.CreateUser(approver) args = api_user.ApiCreateClientApprovalArgs( client_id=client_id, approval=api_user.ApiClientApproval( reason=reason, notified_users=[approver], email_cc_addresses=([email_cc_address] if email_cc_address else []))) handler = api_user.ApiCreateClientApprovalHandler() result = handler.Handle( args, token=access_control.ACLToken(username=requestor)) return result.id
def GrantHuntApproval(self, hunt_id, requestor=None, approval_id=None, approver="approver", admin=True): """Grants an approval for a given hunt.""" if not approval_id: raise ValueError("approval_id can't be empty.") if not requestor: requestor = self.token.username self.CreateUser(requestor) if admin: self.CreateAdminUser(approver) else: self.CreateUser(approver) args = api_user.ApiGrantHuntApprovalArgs(hunt_id=hunt_id, username=requestor, approval_id=approval_id) handler = api_user.ApiGrantHuntApprovalHandler() handler.Handle(args, token=access_control.ACLToken(username=approver))
def ApprovalRevokeRaw(aff4_path, token): """Revokes an approval for a given token. This method requires raw datastore access to manipulate approvals directly. Args: aff4_path: The aff4_path or client id the approval should be created for. token: The token that should be revoked. """ try: urn = rdf_client.ClientURN(aff4_path) except type_info.TypeValueError: urn = rdfvalue.RDFURN(aff4_path) approval_urn = aff4.ROOT_URN.Add("ACL").Add(urn.Path()).Add( token.username).Add(utils.EncodeReasonString(token.reason)) super_token = access_control.ACLToken(username="******") super_token.supervisor = True approval_request = aff4.FACTORY.Open(approval_urn, mode="rw", token=super_token) approval_request.DeleteAttribute(approval_request.Schema.APPROVER) approval_request.Close()
def BuildToken(request, execution_time): """Build an ACLToken from the request.""" # The request.args dictionary will also be filled on HEAD calls. if request.method in ["GET", "HEAD"]: reason = request.args.get("reason", "") elif request.method in ["POST", "DELETE", "PATCH"]: # The header X-GRR-Reason is set in api-service.js. reason = utils.SmartUnicode( urllib2.unquote(request.headers.get("X-Grr-Reason", ""))) # We assume that request.user contains the username that we can trust. # No matter what authentication method is used, the WebAuthManager is # responsible for authenticating the userand setting request.user to # a correct value (see gui/webauth.py). # # The token that's built here will be later used to find an API router, # get the ApiCallHandler from the router, and then to call the handler's # Handle() method. API router will be responsible for all the ACL checks. token = access_control.ACLToken(username=request.user, reason=reason, process="GRRAdminUI", expiry=rdfvalue.RDFDatetime.Now() + execution_time) for field in ["Remote_Addr", "X-Forwarded-For"]: remote_addr = request.headers.get(field, "") if remote_addr: token.source_ips.append(remote_addr) return token
def CreateHuntFixtureWithTwoClients(): token = access_control.ACLToken(username="******", reason="test") # Ensure that clients list is empty root = aff4.FACTORY.Open(aff4.ROOT_URN, token=token) for client_urn in root.ListChildren(): if aff4_grr.VFSGRRClient.CLIENT_ID_RE.match(client_urn.Basename()): data_store.DB.DeleteSubject(client_urn) # Add 2 distinct clients client_id = "C.1%015d" % 0 fd = aff4.FACTORY.Create(rdf_client.ClientURN(client_id), aff4_grr.VFSGRRClient, token=token) fd.Set(fd.Schema.SYSTEM("Windows")) fd.Set(fd.Schema.CLOCK(2336650631137737)) fd.Close() client_id = "C.1%015d" % 1 fd = aff4.FACTORY.Create(rdf_client.ClientURN(client_id), aff4_grr.VFSGRRClient, token=token) fd.Set(fd.Schema.SYSTEM("Linux")) fd.Set(fd.Schema.CLOCK(2336650631137737)) fd.Close()
def RunOnce(self): """Initializes StatsStore and StatsStoreWorker.""" # SetUID is required to create and write to aff4:/stats_store token = access_control.ACLToken(username="******").SetUID() global STATS_STORE STATS_STORE = aff4.FACTORY.Create(None, StatsStore, mode="w", token=token) try: STATS_STORE.Flush() except access_control.UnauthorizedAccess: logging.info( "Not writing aff4:/stats_store due to lack of permissions.") # We don't need StatsStoreWorker if there's no StatsStore.process_id in # the config. stats_process_id = config.CONFIG["StatsStore.process_id"] if not stats_process_id: return stats_store_worker = StatsStoreWorker(STATS_STORE, stats_process_id) stats_store_worker.RunAsync()
def __init__(self, thread_name="grr_cron", sleep=60 * 5): self.thread_name = thread_name self.sleep = sleep # SetUID is required to write cronjobs under aff4:/cron/ self.token = access_control.ACLToken(username="******", reason="Implied.").SetUID()
def testDoesNotShowHuntCreatedByAnotherUser(self): self.CreateSampleHunt( "foo", token=access_control.ACLToken(username="******")) self.Open("/") self.WaitUntil( self.IsElementPresent, "css=grr-user-dashboard " "div[name=RecentlyCreatedHunts]:contains('None')")
def Create2HuntsForDifferentUsers(self): # Create 2 hunts. Hunt1 by "otheruser" and hunt2 by us. # Both hunts will be approved by user "approver". hunt1_id = self.CreateSampleHunt(token=access_control.ACLToken( username="******")) hunt2_id = self.CreateSampleHunt(token=access_control.ACLToken( username=self.token.username)) self.CreateAdminUser("approver") self.RequestAndGrantHuntApproval(hunt1_id.Basename(), reason=self.reason, approver="approver", requestor="otheruser") self.RequestAndGrantHuntApproval(hunt2_id.Basename(), reason=self.reason, approver="approver", requestor=self.token.username)
def testCheckFlowRequestLimit(self): # Create a flow with test_lib.FakeTime(self.BASE_TIME): flow.GRRFlow.StartFlow( client_id=self.client_id, flow_name=flow_test_lib.DummyLogFlow.__name__, token=self.token) # One day + 1s later with test_lib.FakeTime(self.BASE_TIME + 86400 + 1): flow.GRRFlow.StartFlow( client_id=self.client_id, flow_name=flow_test_lib.DummyLogFlow.__name__, token=self.token) # Disable the dup interval checking by setting it to 0. throttler = throttle.FlowThrottler( daily_req_limit=2, dup_interval=rdfvalue.Duration("0s")) # Should succeeed, only one flow present in the 1 day window. throttler.EnforceLimits(self.client_id, self.token.username, flow_test_lib.DummyLogFlow.__name__, None, token=self.token) # Start some more flows with a different user token2 = access_control.ACLToken(username="******", reason="Running tests") flow.GRRFlow.StartFlow( client_id=self.client_id, flow_name=flow_test_lib.DummyLogFlow.__name__, token=token2) flow.GRRFlow.StartFlow( client_id=self.client_id, flow_name=flow_test_lib.DummyLogFlow.__name__, token=token2) # Should still succeed, since we count per-user throttler.EnforceLimits(self.client_id, self.token.username, flow_test_lib.DummyLogFlow.__name__, None, token=self.token) # Add another flow at current time flow.GRRFlow.StartFlow( client_id=self.client_id, flow_name=flow_test_lib.DummyLogFlow.__name__, token=self.token) with self.assertRaises( throttle.ErrorDailyFlowRequestLimitExceeded): throttler.EnforceLimits(self.client_id, self.token.username, flow_test_lib.DummyLogFlow.__name__, None, token=self.token)
def TerminateFlow(cls, flow_id, reason=None, status=None, token=None, force=False): """Terminate a flow. Args: flow_id: The flow session_id to terminate. reason: A reason to log. status: Status code used in the generated status message. token: The access token to be used for this request. force: If True then terminate locked flows hard. Raises: FlowError: If the flow can not be found. """ if not force: flow_obj = aff4.FACTORY.OpenWithLock( flow_id, aff4_type=GRRFlow, blocking=True, token=token) else: flow_obj = aff4.FACTORY.Open( flow_id, aff4_type=GRRFlow, mode="rw", token=token) if not flow_obj: raise FlowError("Could not terminate flow %s" % flow_id) with flow_obj: runner = flow_obj.GetRunner() if not runner.IsRunning(): return if token is None: token = access_control.ACLToken() if reason is None: reason = "Manual termination by console." # This calls runner.Terminate to kill the flow runner.Error(reason, status_code=status) flow_obj.Log("Terminated by user {0}. Reason: {1}".format( token.username, reason)) # From now on we run with supervisor access super_token = token.SetUID() # Also terminate its children children_to_kill = aff4.FACTORY.MultiOpen( flow_obj.ListChildren(), token=super_token, aff4_type=GRRFlow) for child_obj in children_to_kill: cls.TerminateFlow( child_obj.urn, reason="Parent flow terminated.", token=super_token, force=force)
def testDeleteHuntIsAccessCheckedIfUserIsNotCreator(self): hunt = self.CreateHunt() args = api_hunt.ApiDeleteHuntArgs(hunt_id=hunt.urn.Basename()) self.CheckMethodIsAccessChecked( self.router.DeleteHunt, "CheckHuntAccess", args=args, token=access_control.ACLToken(username="******"))
def main(argv): del argv # Unused. config.CONFIG.AddContext(contexts.TEST_CONTEXT, "Context for running tests.") server_startup.Init() for handler in logging.getLogger().handlers: handler.addFilter(E2ELogFilter()) data_store.default_token = access_control.ACLToken( username=getpass.getuser(), reason="End-to-end tests") return RunEndToEndTests()
def testNoReasonShouldSearchForApprovals(self): token_without_reason = access_control.ACLToken(username="******") client_id = self.SetupClient(0) self.RequestAndGrantClientApproval(client_id, requestor="unknown", reason="I have one!") self.access_manager.CheckClientAccess(token_without_reason, client_id) # Check that token's reason got modified in the process: self.assertEqual(token_without_reason.reason, "I have one!")
def _BuildToken(self, request, execution_time): """Build an ACLToken from the request.""" token = access_control.ACLToken(username=request.user, reason=request.args.get("reason", ""), process="GRRAdminUI", expiry=rdfvalue.RDFDatetime.Now() + execution_time) for field in ["Remote_Addr", "X-Forwarded-For"]: remote_addr = request.headers.get(field, "") if remote_addr: token.source_ips.append(remote_addr) return token
def __init__(self): super(FullAccessControlManager, self).__init__() self.acl_cache = utils.AgeBasedCache(max_size=10000, max_age=self.approval_cache_time) self.super_token = access_control.ACLToken( username="******").SetUID() self.helpers = { "w": self._CreateWriteAccessHelper(), "r": self._CreateReadAccessHelper(), "q": self._CreateQueryAccessHelper() }
def testFiltersHuntsByCreator(self): for i in range(5): self.CreateHunt(description="foo_hunt_%d" % i, token=access_control.ACLToken(username="******")) for i in range(3): self.CreateHunt(description="bar_hunt_%d" % i, token=access_control.ACLToken(username="******")) result = self.handler.Handle(hunt_plugin.ApiListHuntsArgs( created_by="user-foo", active_within="1d"), token=self.token) self.assertEqual(len(result.items), 5) for item in result.items: self.assertEqual(item.creator, "user-foo") result = self.handler.Handle(hunt_plugin.ApiListHuntsArgs( created_by="user-bar", active_within="1d"), token=self.token) self.assertEqual(len(result.items), 3) for item in result.items: self.assertEqual(item.creator, "user-bar")
def testSetsSettingsForUserCorrespondingToToken(self): settings = aff4_users.GUISettings(mode="ADVANCED", canary_mode=True) user = user_plugin.ApiGrrUser(settings=settings) self.handler.Handle(user, token=access_control.ACLToken(username="******")) # Check that settings for user "foo" were applied. fd = aff4.FACTORY.Open("aff4:/users/foo", token=self.token) self.assertEqual(fd.Get(fd.Schema.GUI_SETTINGS), settings) # Check that settings were applied in relational db. u = data_store.REL_DB.ReadGRRUser("foo") self.assertEqual(settings.mode, u.ui_mode) self.assertEqual(settings.canary_mode, u.canary_mode)
def main(argv): """Main.""" del argv # Unused. config.CONFIG.AddContext(contexts.WORKER_CONTEXT, "Context applied when running a worker.") # Initialise flows and config_lib server_startup.Init() fleetspeak_connector.Init() token = access_control.ACLToken(username="******").SetUID() worker_obj = worker.GRRWorker(token=token) worker_obj.Run()
def testDeleteHunt(self): # This needs to be created by a different user so we can test the # approval dialog. hunt = self.CreateSampleHunt( stopped=True, token=access_control.ACLToken(username="******", reason="test")) self.Open("/") self.WaitUntil(self.IsElementPresent, "client_query") self.Click("css=a[grrtarget=hunts]") self.WaitUntil(self.IsTextPresent, "GenericHunt") # Select a Hunt. self.Click("css=td:contains('GenericHunt')") # Click on delete button. self.Click("css=button[name=DeleteHunt]") self.WaitUntil(self.IsTextPresent, "Delete this hunt") # Click on Proceed. self.Click("css=button[name=Proceed]") # This should be rejected now and a form request is made. self.WaitUntil(self.IsTextPresent, "Create a new approval") self.Click("css=grr-request-approval-dialog button[name=Cancel]") # Wait for dialog to disappear. self.WaitUntilNot(self.IsVisible, "css=.modal-open") # Now create an approval. self.RequestAndGrantHuntApproval(hunt.session_id.Basename()) # Select a hunt again, as it's deselected after approval dialog # disappears. TODO(user): if this behavior is not convenient, fix it. self.Click("css=td:contains('GenericHunt')") # Click on Delete button and check that dialog appears. self.Click("css=button[name=DeleteHunt]") self.WaitUntil(self.IsTextPresent, "Delete this hunt") # Click on "Proceed" and wait for success label to appear. # Also check that "Proceed" button gets disabled. self.Click("css=button[name=Proceed]") self.WaitUntil(self.IsTextPresent, "Hunt deleted successfully!") self.assertFalse(self.IsElementPresent("css=button[name=Proceed]")) # Click on "Cancel" and check that dialog disappears. self.Click("css=button[name=Close]") self.WaitUntilNot(self.IsVisible, "css=.modal-open")
def __init__(self, certificate, private_key, max_queue_size=50, message_expiry_time=120, max_retransmission_time=10, threadpool_prefix="grr_threadpool"): # Identify ourselves as the server. self.token = access_control.ACLToken(username="******", reason="Implied.") self.token.supervisor = True if data_store.RelationalDBReadEnabled(): self._communicator = RelationalServerCommunicator( certificate=certificate, private_key=private_key) else: self._communicator = ServerCommunicator(certificate=certificate, private_key=private_key, token=self.token) self.message_expiry_time = message_expiry_time self.max_retransmission_time = max_retransmission_time self.max_queue_size = max_queue_size self.thread_pool = threadpool.ThreadPool.Factory( threadpool_prefix, min_threads=2, max_threads=config.CONFIG["Threadpool.size"]) self.thread_pool.Start() # There is only a single session id that we accept unauthenticated # messages for, the one to enroll new clients. self.unauth_allowed_session_id = rdfvalue.SessionID( queue=queues.ENROLLMENT, flow_name="Enrol") # Some well known flows are run on the front end. available_wkfs = flow.WellKnownFlow.GetAllWellKnownFlows( token=self.token) whitelist = set(config.CONFIG["Frontend.well_known_flows"]) available_wkf_set = set(available_wkfs) unknown_flows = whitelist - available_wkf_set if unknown_flows: raise ValueError("Unknown flows in Frontend.well_known_flows: %s" % ",".join(unknown_flows)) self.well_known_flows = { flow_name: available_wkfs[flow_name] for flow_name in whitelist & available_wkf_set }
def main(argv): """Main.""" del argv # Unused. banner = ("\nWelcome to the GRR console\n") config.CONFIG.AddContext(contexts.COMMAND_LINE_CONTEXT) config.CONFIG.AddContext( contexts.CONSOLE_CONTEXT, "Context applied when running the console binary.") server_startup.Init() fleetspeak_connector.Init() # To make the console easier to use, we make a default token which will be # used in StartFlow operations. data_store.default_token = access_control.ACLToken( username=getpass.getuser(), reason=flags.FLAGS.reason) locals_vars = { "__name__": "GRR Console", "l": Lister, "lc": GetChildrenList, "o": aff4.FACTORY.Open, # Bring some symbols from other modules into the console's # namespace. "StartFlowAndWait": flow_utils.StartFlowAndWait, "StartFlowAndWorker": console_utils.StartFlowAndWorker, } locals_vars.update(globals()) # add global variables to console if flags.FLAGS.client is not None: locals_vars["client"], locals_vars["token"] = console_utils.OpenClient( client_id=flags.FLAGS.client) if flags.FLAGS.code_to_execute: logging.info("Running code from flag: %s", flags.FLAGS.code_to_execute) exec(flags.FLAGS.code_to_execute) # pylint: disable=exec-used elif flags.FLAGS.command_file: logging.info("Running code from file: %s", flags.FLAGS.command_file) execfile(flags.FLAGS.command_file) if (flags.FLAGS.exit_on_complete and (flags.FLAGS.code_to_execute or flags.FLAGS.command_file)): return else: # We want the normal shell. locals_vars.update(globals()) # add global variables to console ipshell.IPShell(argv=[], user_ns=locals_vars, banner=banner)
def testEmptySubjectShouldRaise(self): token = access_control.ACLToken(username="******") with self.assertRaises(ValueError): self.access_manager.CheckClientAccess(token, "") with self.assertRaises(ValueError): self.access_manager.CheckHuntAccess(token, "") with self.assertRaises(ValueError): self.access_manager.CheckCronJobAccess(token, "") with self.assertRaises(ValueError): self.access_manager.CheckDataStoreAccess(token, [""], requested_access="r")
def RequestAndGrantClientApproval(client_id, token=None, approver="approver", reason="testing"): token = token or GetToken() ApprovalRequest(client_id, token=token, approver=approver, reason=reason) user = aff4.FACTORY.Create("aff4:/users/%s" % approver, users.GRRUser, token=token.SetUID()) user.Flush() approver_token = access_control.ACLToken(username=approver) security.ClientApprovalGrantor(reason=reason, delegate=token.username, subject_urn=rdf_client.ClientURN(client_id), token=approver_token).Grant()