def _CheckAccess(self, username, subject_id, approval_type):
        """Checks access to a given subject by a given user."""
        precondition.AssertType(subject_id, Text)

        cache_key = (username, subject_id, approval_type)
        try:
            self.acl_cache.Get(cache_key)
            APPROVAL_SEARCHES.Increment(fields=["-", "cache"])
            return True
        except KeyError:
            APPROVAL_SEARCHES.Increment(fields=["-", "reldb"])

        approvals = data_store.REL_DB.ReadApprovalRequests(
            username,
            approval_type,
            subject_id=subject_id,
            include_expired=False)

        errors = []
        for approval in approvals:
            try:
                approval_checks.CheckApprovalRequest(approval)
                self.acl_cache.Put(cache_key, True)
                return
            except access_control.UnauthorizedAccess as e:
                errors.append(e)

        subject = approval_checks.BuildLegacySubject(subject_id, approval_type)
        if not errors:
            raise access_control.UnauthorizedAccess("No approval found.",
                                                    subject=subject)
        else:
            raise access_control.UnauthorizedAccess(" ".join(
                str(e) for e in errors),
                                                    subject=subject)
Esempio n. 2
0
    def CreateFlow(self, args, context=None):
        if not args.client_id:
            raise ValueError("client_id must be provided")

        if args.flow.name in self.allowed_file_finder_flow_names:
            self._CheckFileFinderArgs(args.flow.args)
            override_flow_name = self.effective_file_finder_flow_name
            override_flow_args = self._FixFileFinderArgs(args.flow.args)
            throttler = self._GetFileFinderThrottler()
        elif args.flow.name in self.allowed_artifact_collector_flow_names:
            self._CheckArtifactCollectorFlowArgs(args.flow.args)
            override_flow_name = self.effective_artifact_collector_flow_name
            override_flow_args = None
            throttler = self._GetArtifactCollectorFlowThrottler()
        else:
            raise access_control.UnauthorizedAccess(
                "Creating arbitrary flows (%s) is not allowed." %
                args.flow.name)

        try:
            throttler.EnforceLimits(args.client_id.ToString(),
                                    context.username, args.flow.name,
                                    args.flow.args)
        except throttle.DuplicateFlowError as e:
            # If a similar flow did run recently, just return it.
            return ApiRobotReturnDuplicateFlowHandler(flow_id=e.flow_id)
        except throttle.DailyFlowRequestLimitExceededError as e:
            # Raise UnauthorizedAccess so that the user gets an HTTP 403.
            raise access_control.UnauthorizedAccess(str(e))

        return ApiRobotCreateFlowHandler(override_flow_name=override_flow_name,
                                         override_flow_args=override_flow_args)
  def _CheckAccess(self, username, subject_id, approval_type):
    """Checks access to a given subject by a given user."""
    utils.AssertType(subject_id, unicode)

    cache_key = (username, subject_id, approval_type)
    try:
      self.acl_cache.Get(cache_key)
      stats.STATS.IncrementCounter("approval_searches", fields=["-", "cache"])
      return True
    except KeyError:
      stats.STATS.IncrementCounter("approval_searches", fields=["-", "reldb"])

    approvals = data_store.REL_DB.ReadApprovalRequests(
        username, approval_type, subject_id=subject_id, include_expired=False)

    errors = []
    for approval in approvals:
      try:
        approval_checks.CheckApprovalRequest(approval)
        self.acl_cache.Put(cache_key, True)
        return
      except access_control.UnauthorizedAccess as e:
        errors.append(e)

    subject = approval_checks.BuildLegacySubject(subject_id, approval_type)
    if not errors:
      raise access_control.UnauthorizedAccess(
          "No approval found.", subject=subject)
    else:
      raise access_control.UnauthorizedAccess(
          " ".join(utils.SmartStr(e) for e in errors), subject=subject)
Esempio n. 4
0
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
Esempio n. 5
0
    def CreateFlow(self, args, token=None):
        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)
        except throttle.ErrorDailyFlowRequestLimitExceeded as e:
            # Raise UnauthorizedAccess so that the user gets an HTTP 403.
            raise access_control.UnauthorizedAccess(str(e))

        return ApiRobotCreateFlowHandler(robot_id=self.params.robot_id,
                                         override_flow_args=override_flow_args)
Esempio n. 6
0
    def _CheckFlowRobotId(self, client_id, flow_id, token=None):
        # We don't use robot ids in REL_DB, but simply check that flow's creator is
        # equal to the user making the request.
        # TODO(user): get rid of robot id logic as soon as AFF4 is gone.
        if data_store.RelationalDBEnabled():
            flow_obj = data_store.REL_DB.ReadFlowObject(
                str(client_id), str(flow_id))
            if flow_obj.creator != token.username:
                raise access_control.UnauthorizedAccess(
                    "Flow %s (client %s) has to be created "
                    "by the user making the request." % (flow_id, client_id))
            return flow_obj.flow_class_name
        else:
            flow_urn = flow_id.ResolveClientFlowURN(client_id)
            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.Name()
Esempio n. 7
0
  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.allow_artifacts:
        raise access_control.UnauthorizedAccess(
            "Artifact %s is not whitelisted." % name)
Esempio n. 8
0
    def Grant(self):
        """Create the Approval object and notify the Approval Granter."""

        approvals_root_urn = aff4.ROOT_URN.Add("ACL").Add(
            self.subject_urn.Path()).Add(self.delegate)
        children_urns = list(aff4.FACTORY.ListChildren(approvals_root_urn))
        if not children_urns:
            raise access_control.UnauthorizedAccess(
                "No approval found for user %s" %
                utils.SmartStr(self.token.username),
                subject=self.subject_urn)

        approvals = aff4.FACTORY.MultiOpen(children_urns,
                                           mode="r",
                                           aff4_type=Approval,
                                           token=self.token)
        found_approval_urn = None
        for approval in approvals:
            approval_reason = approval.Get(approval.Schema.REASON)
            if (utils.SmartUnicode(approval_reason) == utils.SmartUnicode(
                    self.reason)
                    and (not found_approval_urn
                         or approval_reason.age > found_approval_urn.age)):
                found_approval_urn = approval.urn
                found_approval_urn.age = approval_reason.age

        if not found_approval_urn:
            raise access_control.UnauthorizedAccess(
                "No approval with reason '%s' found for user %s" %
                (utils.SmartStr(
                    self.reason), utils.SmartStr(self.token.username)),
                subject=self.subject_urn)

        # This object must already exist.
        try:
            approval_request = aff4.FACTORY.Open(found_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")

        with approval_request:
            # We are now an approver for this request.
            approval_request.AddAttribute(
                approval_request.Schema.APPROVER(self.token.username))

        return found_approval_urn
Esempio n. 9
0
  def CheckMethodIsAccessChecked(self,
                                 method,
                                 access_type,
                                 args=None,
                                 context=None):
    context = context or self.context

    # Check that legacy access control manager is called and that the method
    # is then delegated.
    method(args, context=context)
    self.assertTrue(getattr(self.access_checker_mock, access_type).called)
    getattr(self.delegate_mock, method.__name__).assert_called_with(
        args, context=context)

    self.delegate_mock.reset_mock()
    self.access_checker_mock.reset_mock()

    try:
      # Check that when exception is raised by legacy manager, the delegate
      # method is not called.
      getattr(self.access_checker_mock,
              access_type).side_effect = access_control.UnauthorizedAccess("")

      with self.assertRaises(access_control.UnauthorizedAccess):
        method(args, context=context)

      self.assertTrue(getattr(self.access_checker_mock, access_type).called)
      self.assertFalse(getattr(self.delegate_mock, method.__name__).called)

    finally:
      getattr(self.access_checker_mock, access_type).side_effect = None
      self.delegate_mock.reset_mock()
      self.access_checker_mock.reset_mock()
Esempio n. 10
0
    def testCopyACLErrorIsCorrectlyDisplayed(self):
        args = rdf_file_finder.FileFinderArgs(paths=["a/b/*"])
        flow.StartAFF4Flow(flow_name=flows_file_finder.FileFinder.__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('FileFinder')")

        # Stub out the API handler to guarantee failure.
        with mock.patch.object(
                api_call_router_with_approval_checks.
                ApiCallRouterWithApprovalChecks,
                "CreateFlow") as create_flow_mock:
            # The error has to be an ACL error, since ACL errors are not handled
            # by the global errors handler and are not automatically displayed.
            create_flow_mock.side_effect = [
                access_control.UnauthorizedAccess("oh no!")
            ]

            # Open wizard and launch the copy flow.
            self.Click("css=button[name=copy_flow]")
            self.Click("css=button:contains('Launch')")

        self.WaitUntil(self.IsElementPresent,
                       "css=.modal-dialog .text-danger:contains('oh no!')")

        # Check that closing the dialog doesn't change flow selection.
        self.Click("css=button[name=Close]")
        self.WaitUntil(self.IsElementPresent,
                       "css=grr-client-flows-view tr.row-selected")
Esempio n. 11
0
    def CheckIfCanStartClientFlow(self, username, flow_name):
        """Checks whether a given user can start a given flow."""
        flow_cls = registry.FlowRegistry.FLOW_REGISTRY.get(flow_name)

        if flow_cls is None or not hasattr(
                flow_cls, "category") or not flow_cls.category:
            raise access_control.UnauthorizedAccess(
                "Flow %s can't be started via the API." % flow_name)

        if flow_cls in RESTRICTED_FLOWS:
            try:
                self.CheckIfHasAccessToRestrictedFlows(username)
            except access_control.UnauthorizedAccess as e:
                raise access_control.UnauthorizedAccess(
                    "Not enough permissions to access restricted "
                    f"flow {flow_name}") from e
    def testGetGrrUserReturnsRestrictedTraitsForNonAdminUser(self):
        error = access_control.UnauthorizedAccess("some error")
        self.access_checker_mock.CheckIfUserIsAdmin.side_effect = error
        handler = self.router.GetGrrUser(None, context=self.context)

        self.assertNotEqual(handler.interface_traits,
                            api_user.ApiGrrUserInterfaceTraits().EnableAll())
  def CheckIfUserIsAdmin(self, username):
    """Checks whether the user is an admin."""

    user_obj = data_store.REL_DB.ReadGRRUser(username)
    if user_obj.user_type != user_obj.UserType.USER_TYPE_ADMIN:
      raise access_control.UnauthorizedAccess(
          "User %s is not an admin." % username)
Esempio n. 14
0
    def Handle(self, args, token=None):
        if not args.username:
            raise ValueError("username can't be empty.")

        user_urn = aff4.ROOT_URN.Add("users").Add(args.username)

        events.Events.PublishEvent("Audit",
                                   rdf_events.AuditEvent(user=token.username,
                                                         action="USER_ADD",
                                                         urn=user_urn),
                                   token=token)

        if aff4.FACTORY.ExistsWithType(user_urn,
                                       aff4_type=users.GRRUser,
                                       token=token):
            raise access_control.UnauthorizedAccess(
                "Cannot add user %s: User already exists." % args.username)

        with aff4.FACTORY.Create(user_urn,
                                 aff4_type=users.GRRUser,
                                 mode="rw",
                                 token=token) as fd:

            if args.HasField("password"):
                fd.SetPassword(args.password)

            if args.user_type == args.UserType.USER_TYPE_ADMIN:
                fd.AddLabels(["admin"], owner="GRR")

            return api_user.ApiGrrUser().InitFromAff4Object(fd)
Esempio n. 15
0
    def GetFlow(self, args, context=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, context=context)

        return api_flow.ApiGetFlowHandler()
Esempio n. 16
0
    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()
Esempio n. 17
0
    def ListFlowLogs(self, args, context=None):
        if not self.params.list_flow_logs.enabled:
            raise access_control.UnauthorizedAccess(
                "ListFlowLogs is not allowed by the configuration.")

        self._CheckFlowRobotId(args.client_id, args.flow_id, context=context)

        return api_flow.ApiListFlowLogsHandler()
    def CheckIfCanStartClientFlow(self, username, flow_name):
        """Checks whether a given user can start a given flow."""
        del username  # Unused.

        flow_cls = registry.FlowRegistry.FLOW_REGISTRY.get(flow_name)

        if not flow_cls.category:
            raise access_control.UnauthorizedAccess(
                "Flow %s can't be started via the API." % flow_name)
    def CheckIfCanStartClientFlow(self, username, flow_name):
        """Checks whether a given user can start a given flow."""
        del username  # Unused.

        flow_cls = flow.GRRFlow.GetPlugin(flow_name)

        if not flow_cls.category:
            raise access_control.UnauthorizedAccess(
                "Flow %s can't be started via the API." % flow_name)
Esempio n. 20
0
    def CheckApproversForLabel(self, token, client_id, 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_id: Client ID 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_id,
                    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_id,
                requested_access=token.requested_access)
        return True
Esempio n. 21
0
    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))
Esempio n. 22
0
def CheckUserForLabels(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=aff4_users.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.GetLabelsNames()) == authorized_labels):
      return True
    else:
      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)
Esempio n. 23
0
 def _CheckFlowRobotId(self, client_id, flow_id, context=None):
   # We don't use robot ids in REL_DB, but simply check that flow's creator is
   # equal to the user making the request.
   # TODO(user): get rid of robot id logic as soon as AFF4 is gone.
   flow_obj = data_store.REL_DB.ReadFlowObject(str(client_id), str(flow_id))
   if flow_obj.creator != context.username:
     raise access_control.UnauthorizedAccess(
         "Flow %s (client %s) has to be created "
         "by the user making the request." % (flow_id, client_id))
   return flow_obj.flow_class_name
Esempio n. 24
0
    def _CheckFileFinderArgs(self, flow_args, context=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 = str(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 = str(path)
                if "%%" in str_path:
                    raise access_control.UnauthorizedAccess(
                        "Interpolations are not allowed by the configuration.")
Esempio n. 25
0
    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
Esempio n. 26
0
 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 their "
         "home directory.", subject=subject)
Esempio n. 27
0
def _CheckHasAdminApprovers(approval_request):
    grantors = set(g.grantor_username for g in approval_request.grants)
    for g in grantors:
        user_obj = data_store.REL_DB.ReadGRRUser(g)
        if user_obj.user_type == user_obj.UserType.USER_TYPE_ADMIN:
            return True

    raise access_control.UnauthorizedAccess(
        "Need at least 1 admin approver for access.",
        subject=BuildLegacySubject(approval_request.subject_id,
                                   approval_request.approval_type))
  def CheckIfCanStartClientFlow(self, username, flow_name):
    """Checks whether a given user can start a given flow."""

    flow_cls = flow.GRRFlow.GetPlugin(flow_name)

    if not flow_cls.category:
      raise access_control.UnauthorizedAccess(
          "Flow %s can't be started on a client by non-suid users." % flow_name)

    if flow_cls.AUTHORIZED_LABELS:
      self.CheckIfUserIsAdmin(username)
Esempio n. 29
0
def _CheckHasEnoughGrants(approval_request):
    approvers_required = config.CONFIG["ACL.approvers_required"]
    approvers = set(g.grantor_username for g in approval_request.grants)

    missing = approvers_required - len(approvers)
    if missing > 0:
        msg = ("Need at least %d additional approver%s for access." %
               (missing, "s" if missing > 1 else ""))
        raise access_control.UnauthorizedAccess(
            msg,
            subject=BuildLegacySubject(approval_request.subject_id,
                                       approval_request.approval_type))
def CheckClientLabels(client_id, allow_labels=None, allow_labels_owners=None):
  """Checks a given client against labels/owners allowlists."""
  allow_labels = allow_labels or []
  allow_labels_owners = allow_labels_owners or []

  labels = data_store.REL_DB.ReadClientLabels(str(client_id))

  for label in labels:
    if (label.name in allow_labels and label.owner in allow_labels_owners):
      return

  raise access_control.UnauthorizedAccess(
      "Client %s doesn't have necessary labels." % client_id)