def ValidateAccessAndSubjects(requested_access, subjects): """Does basic requested access validation. Args: requested_access: String consisting or 'r', 'w' and 'q' characters. subjects: A list of subjects that are about to be accessed with a given requested_access. Used for logging purposes only. Returns: True if requested_access is valid. Raises: access_control.UnauthorizedAccess: if requested_access is not valid. ValueError: if subjects list is empty. """ if not requested_access: raise access_control.UnauthorizedAccess( "Must specify requested access type for %s" % subjects) for s in requested_access: if s not in "rwq": raise ValueError("Invalid access requested for %s: %s" % (subjects, requested_access)) if "q" in requested_access and "r" not in requested_access: raise access_control.UnauthorizedAccess( "Invalid access request: query permissions require read permissions " "for %s" % subjects, requested_access=requested_access) return True
def _CheckApprovalsForTokenWithReason(self, token, target): # Build the approval URN. approval_urn = aff4.ROOT_URN.Add("ACL").Add(target.Path()).Add( token.username).Add(utils.EncodeReasonString(token.reason)) try: cached_token = self.acl_cache.Get(approval_urn) stats.STATS.IncrementCounter("approval_searches", fields=["with_reason", "cache"]) token.is_emergency = cached_token.is_emergency return True except KeyError: stats.STATS.IncrementCounter("approval_searches", fields=["with_reason", "data_store"]) try: approval_request = aff4.FACTORY.Open( approval_urn, aff4_type=security.Approval.__name__, mode="r", token=token, age=aff4.ALL_TIMES) if approval_request.CheckAccess(token): # Cache this approval for fast path checking. self.acl_cache.Put(approval_urn, token) return True raise access_control.UnauthorizedAccess( "Approval %s was rejected." % approval_urn, subject=target) except IOError: # No Approval found, reject this request. raise access_control.UnauthorizedAccess( "No approval found for %s." % target, subject=target)
def CheckAccess(self, handler, username): """Check access against ACL file, if defined. Args: handler: handler class object username: username string Raises: access_control.UnauthorizedAccess: If the handler is listed in the ACL file, but the user isn't authorized. Or if enabled_by_default=False and no ACL applies. """ handler_name = handler.__class__.__name__ if handler_name in self.ACLedHandlers(): if not self._CheckPermission(username, handler_name): stats.STATS.IncrementCounter("grr_api_auth_fail", fields=[handler_name, username]) raise access_control.UnauthorizedAccess( "User %s not authorized for handler %s." % (username, handler_name)) elif not handler.enabled_by_default: raise access_control.UnauthorizedAccess( "%s has enabled_by_default=False and no explicit ACL set. Add ACL" " to ACL list (see API.HandlerACLFile config option) to use " "this API" % handler) logging.debug("Authorizing %s for API %s", username, handler_name) stats.STATS.IncrementCounter("grr_api_auth_success", fields=[handler_name, username])
def CheckAccess(self, token): """Enforce a dual approver policy for access.""" namespace, _ = self.urn.Split(2) if namespace != "ACL": raise access_control.UnauthorizedAccess( "Approval object has invalid urn %s." % self.urn, subject=self.urn, requested_access=token.requested_access) user, subject_urn = self.InferUserAndSubjectFromUrn() if user != token.username: raise access_control.UnauthorizedAccess( "Approval object is not for user %s." % token.username, subject=self.urn, requested_access=token.requested_access) now = rdfvalue.RDFDatetime.Now() # Is this an emergency access? break_glass = self.Get(self.Schema.BREAK_GLASS) if break_glass and now < break_glass: # This tags the token as an emergency token. token.is_emergency = True return True # Check that there are enough approvers. approvers = self.GetNonExpiredApprovers() if len(approvers) < config_lib.CONFIG["ACL.approvers_required"]: msg = ("Requires %s approvers for access." % config_lib.CONFIG["ACL.approvers_required"]) raise access_control.UnauthorizedAccess( msg, subject=subject_urn, requested_access=token.requested_access) # Check User labels if self.checked_approvers_label: approvers_with_label = [] # We need to check labels with high privilege since normal users can # inspect other user's labels. for approver in approvers: try: user = aff4.FACTORY.Open( "aff4:/users/%s" % approver, aff4_type=aff4_users.GRRUser, token=token.SetUID()) if self.checked_approvers_label in user.GetLabelsNames(): approvers_with_label.append(approver) except IOError: pass if len(approvers_with_label) < self.min_approvers_with_label: raise access_control.UnauthorizedAccess( "At least %d approver(s) should have '%s' label." % (self.min_approvers_with_label, self.checked_approvers_label), subject=subject_urn, requested_access=token.requested_access) return True
def RenderAjax(self, request, response): """Run the flow for granting access.""" approval_urn = rdfvalue.RDFURN(request.REQ.get("acl", "/")) _, namespace, _ = approval_urn.Split(3) if namespace == "hunts": try: _, _, hunt_id, user, reason = approval_urn.Split() self.subject = rdfvalue.RDFURN(namespace).Add(hunt_id) self.user = user self.reason = utils.DecodeReasonString(reason) except (ValueError, TypeError): raise access_control.UnauthorizedAccess( "Approval object is not well formed.") flow.GRRFlow.StartFlow(flow_name="GrantHuntApprovalFlow", subject_urn=self.subject, reason=self.reason, delegate=self.user, token=request.token) elif namespace == "cron": try: _, _, cron_job_name, user, reason = approval_urn.Split() self.subject = rdfvalue.RDFURN(namespace).Add(cron_job_name) self.user = user self.reason = utils.DecodeReasonString(reason) except (ValueError, TypeError): raise access_control.UnauthorizedAccess( "Approval object is not well formed.") flow.GRRFlow.StartFlow(flow_name="GrantCronJobApprovalFlow", subject_urn=self.subject, reason=self.reason, delegate=self.user, token=request.token) elif aff4.AFF4Object.VFSGRRClient.CLIENT_ID_RE.match(namespace): try: _, client_id, user, reason = approval_urn.Split() self.subject = client_id self.user = user self.reason = utils.DecodeReasonString(reason) except (ValueError, TypeError): raise access_control.UnauthorizedAccess( "Approval object is not well formed.") flow.GRRFlow.StartFlow(client_id=client_id, flow_name="GrantClientApprovalFlow", reason=self.reason, delegate=self.user, subject_urn=rdf_client.ClientURN(self.subject), token=request.token) else: raise access_control.UnauthorizedAccess( "Approval object is not well formed.") return renderers.TemplateRenderer.Layout(self, request, response, apply_template=self.ajax_template)
def CheckACL(self, token, target): # The supervisor may bypass all ACL checks. if token.supervisor: logging.debug(u"ACL access granted to %s on %s. Supervisor: %s", utils.SmartUnicode(token.username), target, token.supervisor) return True # Target may be None for flows not specifying a client. # Only aff4.GRRUser.SYSTEM_USERS can run these flows. if not target: if token.username not in aff4.GRRUser.SYSTEM_USERS: raise access_control.UnauthorizedAccess( "ACL access denied for flow without client_urn for %s" % token.username) return True if not token.reason: raise access_control.UnauthorizedAccess( "Must specify a reason for access.", subject=target) # Build the approval URN. approval_urn = aff4.ROOT_URN.Add("ACL").Add(target.Path()).Add( token.username).Add(utils.EncodeReasonString(token.reason)) try: token.is_emergency = self.acl_cache.Get(approval_urn) logging.debug(u"ACL access granted to %s on %s. Supervisor: %s", utils.SmartUnicode(token.username), target, token.supervisor) return True except KeyError: try: # Retrieve the approval object with superuser privileges so we can check # it. approval_request = aff4.FACTORY.Open(approval_urn, aff4_type="Approval", mode="r", token=self.super_token, age=aff4.ALL_TIMES) if approval_request.CheckAccess(token): # Cache this approval for fast path checking. self.acl_cache.Put(approval_urn, token.is_emergency) logging.debug( u"ACL access granted to %s on %s. Supervisor: %s", utils.SmartUnicode(token.username), target, token.supervisor) return True raise access_control.UnauthorizedAccess( "Approval %s was rejected." % approval_urn, subject=target) except IOError: # No Approval found, reject this request. raise access_control.UnauthorizedAccess( "No approval found for %s." % target, subject=target)
def _CheckArtifactCollectorFlowArgs(self, flow_args): if not self.params.artifact_collector_flow.enabled: raise access_control.UnauthorizedAccess( "ArtifactCollectorFlow flow is not allowed by the configuration") for name in flow_args.artifact_list: if name not in self.params.artifact_collector_flow.artifacts_whitelist: raise access_control.UnauthorizedAccess( "Artifact %s is not whitelisted." % name)
def ValidateRequestedAccess(self, requested_access, subjects): if not requested_access: raise access_control.UnauthorizedAccess( "Must specify requested access type for %s" % subjects) if "q" in requested_access and "r" not in requested_access: raise access_control.UnauthorizedAccess( "Invalid access request: query permissions require read permissions " "for %s" % subjects, requested_access=requested_access)
def UserHasClientApproval(self, subject, token): """Checks if read access for this client is allowed using the given token. Args: subject: Subject below the client level which triggered the check. token: The token to check with. Returns: True if the access is allowed. Raises: UnauthorizedAccess: if the access is rejected. """ client_id, _ = rdfvalue.RDFURN(subject).Split(2) client_urn = rdfvalue.ClientURN(client_id) logging.debug("Checking client approval for %s, %s", client_urn, token) if not token.reason: raise access_control.UnauthorizedAccess( "Must specify a reason for access.", subject=client_urn) # Build the approval URN. approval_urn = aff4.ROOT_URN.Add("ACL").Add(client_urn.Path()).Add( token.username).Add(utils.EncodeReasonString(token.reason)) try: token.is_emergency = self.acl_cache.Get(approval_urn) return True except KeyError: try: # Retrieve the approval object with superuser privileges so we can check # it. approval_request = aff4.FACTORY.Open(approval_urn, aff4_type="Approval", mode="r", token=self.super_token, age=aff4.ALL_TIMES) if approval_request.CheckAccess(token): # Cache this approval for fast path checking. self.acl_cache.Put(approval_urn, token.is_emergency) return True raise access_control.UnauthorizedAccess( "Approval %s was rejected." % approval_urn, subject=client_urn) except IOError: # No Approval found, reject this request. raise access_control.UnauthorizedAccess( "No approval found for client %s." % client_urn, subject=client_urn)
def CheckMethodIsAccessChecked(self, method, access_type, args=None, token=None): token = token or self.token # Check that legacy access control manager is called and that the method # is then delegated. method(args, token=token) self.assertTrue(getattr(self.legacy_manager_mock, access_type).called) getattr(self.delegate_mock, method.__name__).assert_called_with( args, token=token) self.delegate_mock.reset_mock() self.legacy_manager_mock.reset_mock() try: # Check that when exception is raised by legacy manager, the delegate # method is not called. getattr(self.legacy_manager_mock, access_type).side_effect = access_control.UnauthorizedAccess("") with self.assertRaises(access_control.UnauthorizedAccess): method(args, token=token) self.assertTrue(getattr(self.legacy_manager_mock, access_type).called) self.assertFalse(getattr(self.delegate_mock, method.__name__).called) finally: getattr(self.legacy_manager_mock, access_type).side_effect = None self.delegate_mock.reset_mock() self.legacy_manager_mock.reset_mock()
def CheckFlowCanBeStartedAsGlobal(flow_name): """Checks if flow can be started without a client id. Two kinds of flows can be started on clients by unprivileged users: 1) ACL_ENFORCED=False flows, because they're expected to do their own ACL checking and are often used by AdminUI to execute code with elevated privileges. 2) Flows inherited from GRRGlobalFlow, with a category. Having a category means that the flow will be accessible from the UI. Args: flow_name: Name of the flow to check access for. Returns: True if flow is externally accessible. Raises: access_control.UnauthorizedAccess: if flow is not externally accessible. """ flow_cls = flow.GRRFlow.GetPlugin(flow_name) if (not flow_cls.ACL_ENFORCED or aff4.issubclass(flow_cls, flow.GRRGlobalFlow) and flow_cls.category): return True else: raise access_control.UnauthorizedAccess( "Flow %s can't be started globally by non-suid users" % flow_name)
def Layout(self, request, response): """Launch the RequestApproval flow on the backend.""" self.acl = request.REQ.get("acl") source = request.REQ.get("source") if self.acl is None and source != "hash": # NOTE: we have to pass id explicitly because super().Layout() wasn't # called yet, and therefore self.id is None. return self.CallJavascript( response, "GrantAccess.RefreshFromHash", renderer=self.__class__.__name__, id=request.REQ.get("id", hash(self))) # TODO(user): This makes assumptions about the approval URL. approval_urn = rdfvalue.RDFURN(self.acl or "/") components = approval_urn.Split() username = components[-2] namespace = components[1] _, namespace, _ = approval_urn.Split(3) if namespace == "hunts": self.details_renderer = "HuntApprovalDetailsRenderer" self.user = components[3] self.detail_header = "Hunt Information" elif namespace == "cron": self.details_renderer = "CronJobApprovalDetailsRenderer" self.user = components[3] self.detail_header = "Cronjob Information" elif aff4_grr.VFSGRRClient.CLIENT_ID_RE.match(namespace): self.details_renderer = "ClientApprovalDetailsRenderer" self.user = components[2] self.detail_header = "Client Information" else: raise access_control.UnauthorizedAccess( "Approval object is not well formed.") approval_request = aff4.FACTORY.Open( approval_urn, mode="r", age=aff4.ALL_TIMES, token=request.token) self.user = username self.reason = approval_request.Get(approval_request.Schema.REASON) user_token = access_control.ACLToken(username=self.user, reason=self.reason) self.already_approved_text = "" self.btn_cls = "btn btn-success" try: if approval_request.CheckAccess(user_token): self.already_approved_text = "This approval has already been granted!" self.btn_cls = "btn btn-warning" except access_control.UnauthorizedAccess: pass response = renderers.TemplateRenderer.Layout(self, request, response) return self.CallJavascript( response, "GrantAccess.Layout", renderer=self.__class__.__name__, acl=self.acl, details_renderer=self.details_renderer)
def CreateFlow(self, args, token=None): # CreateFlow is used for starting both client flows and global flows. # By not allowing client_id to be empty we explicitly forbid starting # global flows through robot router. # TODO(user): introduce separate API call for starting global flows. if not args.client_id: raise ValueError("client_id must be provided") override_flow_args = None throttler = None if args.flow.name == self.file_finder_flow_name: self._CheckFileFinderArgs(args.flow.args) override_flow_args = self._FixFileFinderArgs(args.flow.args) throttler = self._GetFileFinderThrottler() elif args.flow.name == self.artifact_collector_flow_name: self._CheckArtifactCollectorFlowArgs(args.flow.args) throttler = self._GetArtifactCollectorFlowThrottler() else: raise access_control.UnauthorizedAccess( "Creating arbitrary flows (%s) is not allowed." % args.flow.name) try: throttler.EnforceLimits(args.client_id.ToClientURN(), token.username, args.flow.name, args.flow.args, token=token) except throttle.ErrorFlowDuplicate as e: # If a similar flow did run recently, just return it. return ApiRobotReturnDuplicateFlowHandler(flow_urn=e.flow_urn) return ApiRobotCreateFlowHandler(robot_id=self.params.robot_id, override_flow_args=override_flow_args)
def ValidateToken(self, token, target): """Validate Basic Token Issues.""" # All accesses need a token. if not token: raise access_control.UnauthorizedAccess( "Must give an authorization token for %s" % target, subject=target) # Token must not be expired here. token.CheckExpiry() # Token must have identity if not token.username: raise access_control.UnauthorizedAccess( "Must specify a username for access to %s." % target, subject=target)
def CheckFlowCanBeStartedOnClient(flow_name): """Checks if flow can be started on a particular client. Two kinds of flows can be started on clients by unprivileged users: 1) ACL_ENFORCED=False flows, because they're expected to do their own ACL checking and are often used by AdminUI to execute code with elevated privileges. 2) Flows with a category. Having a category means that the flow will be accessible from the UI. Args: flow_name: Name of the flow to check access for. Returns: True if flow is externally accessible. Raises: access_control.UnauthorizedAccess: if flow is not externally accessible. """ flow_cls = flow.GRRFlow.GetPlugin(flow_name) if not flow_cls.ACL_ENFORCED or flow_cls.category: return True else: raise access_control.UnauthorizedAccess( "Flow %s can't be started on a client by non-suid users." % flow_name)
def CreateFlow(self, args, token=None): # CreateFlow is used for starting both client flows and global flows. # By not allowing client_id to be empty we explicitly forbid starting # global flows through robot router. # TODO(user): introduce separate API call for starting global flows. if not args.client_id: raise ValueError("client_id must be provided") throttler = None if args.flow.name == self.file_finder_flow_name: self._CheckFileFinderArgs(args.flow.args) throttler = self._GetFileFinderThrottler() elif args.flow.name == self.artifact_collector_flow_name: self._CheckArtifactCollectorFlowArgs(args.flow.args) throttler = self._GetArtifactCollectorFlowThrottler() else: raise access_control.UnauthorizedAccess( "Creating arbitrary flows (%s) is not allowed." % args.flow.name) throttler.EnforceLimits(args.client_id, token.username, args.flow.name, args.flow.args, token=token) return ApiRobotCreateFlowHandler(robot_id=self.params.robot_id)
def GetFlow(self, args, token=None): if not self.params.get_flow.enabled: raise access_control.UnauthorizedAccess( "GetFlow is not allowed by the configuration.") self._CheckFlowRobotId(args.client_id, args.flow_id, token=token) return api_flow.ApiGetFlowHandler()
def ListFlowResults(self, args, token=None): if not self.params.list_flow_results.enabled: raise access_control.UnauthorizedAccess( "ListFlowResults is not allowed by the configuration.") self._CheckFlowRobotId(args.client_id, args.flow_id, token=token) return api_flow.ApiListFlowResultsHandler()
def CheckCronJobAccess(self, token, cron_job_urn): """Checks access to a given cron job. Args: token: User credentials token. cron_job_urn: URN of cron job to check. Returns: True if access is allowed, raises otherwise. Raises: access_control.UnauthorizedAccess if access is rejected. """ logging.debug("Checking approval for cron job %s, %s", cron_job_urn, token) if not token.username: raise access_control.UnauthorizedAccess( "Must specify a username for access.", subject=cron_job_urn) if not token.reason: raise access_control.UnauthorizedAccess( "Must specify a reason for access.", subject=cron_job_urn) # Build the approval URN. approval_urn = aff4.ROOT_URN.Add("ACL").Add(cron_job_urn.Path()).Add( token.username).Add(utils.EncodeReasonString(token.reason)) try: approval_request = aff4.FACTORY.Open(approval_urn, aff4_type="Approval", mode="r", token=token, age=aff4.ALL_TIMES) except IOError: # No Approval found, reject this request. raise access_control.UnauthorizedAccess( "No approval found for cron job %s." % cron_job_urn, subject=cron_job_urn) if approval_request.CheckAccess(token): return True else: raise access_control.UnauthorizedAccess( "Approval %s was rejected." % approval_urn, subject=cron_job_urn)
def CheckUserLabels(self, username, authorized_labels, token=None): """Verify that the username has all the authorized_labels set.""" authorized_labels = set(authorized_labels) try: user = aff4.FACTORY.Open("aff4:/users/%s" % username, aff4_type="GRRUser", token=token) # Only return if all the authorized_labels are found in the user's # label list, otherwise raise UnauthorizedAccess. if (authorized_labels.intersection(user.GetLabels()) == authorized_labels): return raise access_control.UnauthorizedAccess( "User %s is missing labels (required: %s)." % (username, authorized_labels)) except IOError: raise access_control.UnauthorizedAccess("User %s not found." % username)
def Start(self): """Create the Approval object and notify the Approval Granter.""" approval_urn = self.BuildApprovalUrn() subject_title = self.BuildSubjectTitle() access_urn = self.BuildAccessUrl() # This object must already exist. try: approval_request = aff4.FACTORY.Open(approval_urn, mode="rw", aff4_type=self.approval_type, token=self.token) except IOError: raise access_control.UnauthorizedAccess( "Approval object does not exist.", requested_access="rw") # We are now an approver for this request. approval_request.AddAttribute( approval_request.Schema.APPROVER(self.token.username)) approval_request.Close(sync=True) # Notify to the user. fd = aff4.FACTORY.Create(aff4.ROOT_URN.Add("users").Add( self.args.delegate), "GRRUser", mode="rw", token=self.token) fd.Notify( "ViewObject", self.args.subject_urn, "%s has granted you access to %s." % (self.token.username, subject_title), self.session_id) fd.Close() template = """ <html><body><h1>Access to %(subject_title)s granted.</h1> The user %(username)s has granted access to %(subject_title)s for the purpose of "%(reason)s". Please click <a href='%(admin_ui)s#%(subject_urn)s'>here</a> to access it. <p>Thanks,</p> <p>The GRR team. </body></html>""" email_alerts.SendEmail(self.args.delegate, self.token.username, "Access to %s granted." % subject_title, template % dict(subject_title=subject_title, username=self.token.username, reason=utils.SmartStr(self.args.reason), admin_ui=config_lib.CONFIG["AdminUI.url"], subject_urn=access_urn), is_html=True)
def InferUserAndSubjectFromUrn(self): """Infers user name and subject urn from self.urn.""" _, cron_str, cron_job_name, user, _ = self.urn.Split(5) if cron_str != "cron": raise access_control.UnauthorizedAccess( "Approval object has invalid urn %s." % self.urn, requested_access=self.token.requested_access) return (user, aff4.ROOT_URN.Add("cron").Add(cron_job_name))
def Layout(self, request, response): """Launch the RequestApproval flow on the backend.""" self.acl = request.REQ.get("acl") source = request.REQ.get("source") if self.acl is None and source != "hash": # NOTE: we have to pass id explicitly because super().Layout() wasn't # called yet, and therefore self.id is None. return self.CallJavascript(response, "GrantAccess.RefreshFromHash", renderer=self.__class__.__name__, id=request.REQ.get("id", hash(self))) # There is a bug in Firefox that strips trailing "="s from get parameters # which is a problem with the base64 padding. To pass the selenium tests, # we have to restore the original string. while len(self.acl.split("/")[-1]) % 4 != 0: self.acl += "=" # TODO(user): This makes assumptions about the approval URL. approval_urn = rdfvalue.RDFURN(self.acl or "/") components = approval_urn.Split() username = components[-2] namespace = components[1] _, namespace, _ = approval_urn.Split(3) if namespace == "hunts": self.details_renderer = "HuntApprovalDetailsRenderer" self.user = components[3] self.detail_header = "Hunt Information" elif namespace == "cron": self.details_renderer = "CronJobApprovalDetailsRenderer" self.user = components[3] self.detail_header = "Cronjob Information" elif aff4.AFF4Object.VFSGRRClient.CLIENT_ID_RE.match(namespace): self.details_renderer = "ClientApprovalDetailsRenderer" self.user = components[2] self.detail_header = "Client Information" else: raise access_control.UnauthorizedAccess( "Approval object is not well formed.") approval_request = aff4.FACTORY.Open(approval_urn, mode="r", token=request.token) self.user = username self.reason = approval_request.Get(approval_request.Schema.REASON) response = renderers.TemplateRenderer.Layout(self, request, response) return self.CallJavascript(response, "GrantAccess.Layout", renderer=self.__class__.__name__, acl=self.acl, details_renderer=self.details_renderer)
def CheckFlowAccess(self, token, flow_name, client_id=None): """Checks access to the given flow. Args: token: User credentials token. flow_name: Name of the flow to check. client_id: Client id of the client where the flow is going to be started. Defaults to None. Returns: True if access is allowed, raises otherwise. Raises: access_control.UnauthorizedAccess if access is rejected. """ client_urn = None if client_id: client_urn = rdfvalue.ClientURN(client_id) if not token: raise access_control.UnauthorizedAccess( "Must give an authorization token for flow %s" % flow_name) # Token must not be expired here. token.CheckExpiry() # The supervisor may bypass all ACL checks. if token.supervisor: return True flow_cls = flow.GRRFlow.GetPlugin(flow_name) # Flows which are not enforced can run all the time. if not flow_cls.ACL_ENFORCED: return True if not client_urn: raise access_control.UnauthorizedAccess( "Mortals are only allowed to run flows on the client.") # This should raise in case of failure. return self.UserHasClientApproval(client_urn, token)
def CheckApproversForLabel(self, token, client_urn, requester, approvers, label): """Checks if requester and approvers have approval privileges for labels. Checks against list of approvers for each label defined in approvers.yaml to determine if the list of approvers is sufficient. Args: token: user token client_urn: ClientURN object of the client requester: username string of person requesting approval. approvers: list of username strings that have approved this client. label: label strings to check approval privs for. Returns: True if access is allowed, raises otherwise. """ auth = self.reader.GetAuthorizationForSubject(label) if not auth: # This label isn't listed in approvers.yaml return True if auth.requester_must_be_authorized: if not self.CheckPermissions(requester, label): raise access_control.UnauthorizedAccess( "User %s not in %s or groups:%s for %s" % (requester, auth.users, auth.groups, label), subject=client_urn, requested_access=token.requested_access) approved_count = 0 for approver in approvers: if self.CheckPermissions(approver, label) and approver != requester: approved_count += 1 if approved_count < auth.num_approvers_required: raise access_control.UnauthorizedAccess( "Found %s approvers for %s, needed %s" % (approved_count, label, auth.num_approvers_required), subject=client_urn, requested_access=token.requested_access) return True
def _CheckFileFinderArgs(self, flow_args, token=None): ffparams = self.params.file_finder_flow if not ffparams.enabled: raise access_control.UnauthorizedAccess( "FileFinder flow is not allowed by the configuration.") if not ffparams.globs_allowed: for path in flow_args.paths: str_path = utils.SmartStr(path) if "*" in str_path: raise access_control.UnauthorizedAccess( "Globs are not allowed by the configuration.") if not ffparams.interpolations_allowed: for path in flow_args.paths: str_path = utils.SmartStr(path) if "%%" in str_path: raise access_control.UnauthorizedAccess( "Interpolations are not allowed by the configuration.")
def IsHomeDir(self, subject, token): """Checks user access permissions for paths under aff4:/users.""" h = CheckAccessHelper("IsHomeDir") h.Allow("aff4:/users/%s" % token.username) h.Allow("aff4:/users/%s/*" % token.username) try: return h.CheckAccess(subject, token) except access_control.UnauthorizedAccess: raise access_control.UnauthorizedAccess("User can only access his " "home directory.", subject=subject)
def _CheckFlowRobotId(self, client_id, flow_id, token=None): flow_urn = flow_id.ResolveClientFlowURN(client_id, token=token) fd = aff4.FACTORY.Open(flow_urn, aff4_type=flow.GRRFlow, token=token) needed_label_name = LABEL_NAME_PREFIX + self.params.robot_id if needed_label_name not in fd.GetLabelsNames(): raise access_control.UnauthorizedAccess( "Flow %s (client %s) does not have a proper robot id label set." % (flow_id, client_id)) return fd
def ValidateToken(token, targets): """Does basic token validation. Args: token: User's credentials as access_control.ACLToken. targets: List of targets that were meant to be accessed by the token. This is used for logging purposes only. Returns: True if token is valid. Raises: access_control.UnauthorizedAccess: if token is not valid. ValueError: if targets list is empty. """ def GetSubjectForError(): if len(targets) == 1: return list(targets)[0] else: return None # All accesses need a token. if not token: raise access_control.UnauthorizedAccess( "Must give an authorization token for %s" % targets, subject=GetSubjectForError()) # Token must not be expired here. token.CheckExpiry() # Token must have identity if not token.username: raise access_control.UnauthorizedAccess( "Must specify a username for access to %s." % targets, subject=GetSubjectForError()) return True
def CheckClientLabels(self, client_id, token=None): has_label = False with aff4.FACTORY.Open(client_id.ToClientURN(), aff4_type=aff4_grr.VFSGRRClient, token=token) as fd: for label in fd.GetLabels(): if (label.name in self.labels_whitelist and label.owner in self.labels_owners_whitelist): has_label = True break if not has_label: raise access_control.UnauthorizedAccess( "Client %s doesn't have necessary labels." % utils.SmartStr(client_id))