示例#1
0
    def _CheckAccess(self, username, subject_id, approval_type):
        """Checks access to a given subject by a given user."""
        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(
            utils.SmartStr(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)
示例#2
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
  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)
示例#4
0
  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.CONFIG["ACL.approvers_required"]:
      msg = ("Requires %s approvers for access." %
             config.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 _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)
示例#6
0
    def testGetGrrUserReturnsRestrictedTraitsForNonAdminUser(self):
        error = access_control.UnauthorizedAccess("some error")
        self.access_checker_mock.CheckIfUserIsAdmin.side_effect = error
        handler = self.router.GetGrrUser(None, token=self.token)

        self.assertNotEqual(handler.interface_traits,
                            api_user.ApiGrrUserInterfaceTraits().EnableAll())
示例#7
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",
                                   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)
示例#8
0
    def testCopyACLErrorIsCorrectlyDisplayed(self):
        args = rdf_file_finder.FileFinderArgs(paths=["a/b/*"])
        flow.GRRFlow.StartFlow(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")
示例#9
0
    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)
示例#10
0
  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()
示例#11
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()
示例#12
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
示例#13
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))
示例#14
0
    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
示例#15
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))
示例#16
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
示例#17
0
  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.")
示例#18
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)
示例#19
0
    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)
示例#20
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)
示例#21
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))
示例#22
0
    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))
示例#23
0
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
示例#24
0
    def CheckAccess(self, subject, token):
        """Checks for access to given subject with a given token.

    CheckAccess runs given subject through all "allow" clauses that
    were previously registered with Allow() calls. It returns True on
    first match and raises access_control.UnauthorizedAccess if there
    are no matches or if any of the additional checks fails.

    Args:
      subject: RDFURN of the subject that will be checked for access.
      token: User credentials token.

    Returns:
      True if access is granted.

    Raises:
      access_control.UnauthorizedAccess if access is rejected.
    """
        subject = rdfvalue.RDFURN(subject)
        subject_str = subject.SerializeToString()

        for check_tuple in self.checks:
            regex_text, regex, require, require_args, require_kwargs = check_tuple

            match = regex.match(subject_str)
            if not match:
                continue

            if require:
                # If require() fails, it raises access_control.UnauthorizedAccess.
                require(subject, token, *require_args, **require_kwargs)

            logging.debug(
                u"Datastore access granted to %s on %s by pattern: %s "
                u"with reason: %s (require=%s, require_args=%s, "
                u"require_kwargs=%s, helper_name=%s)",
                utils.SmartUnicode(token.username),
                utils.SmartUnicode(subject_str),
                utils.SmartUnicode(regex_text),
                utils.SmartUnicode(token.reason), require, require_args,
                require_kwargs, self.helper_name)
            return True

        logging.warn("Datastore access denied to %s (no matched rules)",
                     subject_str)
        raise access_control.UnauthorizedAccess(
            "Access to %s rejected: (no matched rules)." % subject,
            subject=subject)
示例#25
0
  def GetFlowFilesArchive(self, args, token=None):
    if not self.params.get_flow_files_archive.enabled:
      raise access_control.UnauthorizedAccess(
          "GetFlowFilesArchive is not allowed by the configuration.")

    fd = self._CheckFlowRobotId(args.client_id, args.flow_id, token=token)

    options = self.params.get_flow_files_archive

    if (options.skip_glob_checks_for_artifact_collector and
        fd.Name() == self.artifact_collector_flow_name):
      return api_flow.ApiGetFlowFilesArchiveHandler()
    else:
      return api_flow.ApiGetFlowFilesArchiveHandler(
          path_globs_blacklist=options.path_globs_blacklist,
          path_globs_whitelist=options.path_globs_whitelist)
示例#26
0
def GetDefaultToken(token):
  """Returns the provided token or the default token.

  Args:
    token: A token or None.

  Raises:
    access_control.UnauthorizedAccess, if no token was provided.
  """
  if token is None:
    token = default_token

  if not isinstance(token, access_control.ACLToken):
    raise access_control.UnauthorizedAccess(
        "Token is not properly specified. It should be an "
        "instance of grr.lib.access_control.ACLToken()")

  return token
示例#27
0
    def testWhenAuthMgrActiveRaisesIfAuthMgrRaises(self, mock_mgr):
        data_store.REL_DB.AddClientLabels(self.client.client_id, "GRR",
                                          ["foo"])

        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

        # CheckApproversForLabel should raise.
        error = access_control.UnauthorizedAccess("some error")
        mock_mgr.CheckApproversForLabel.side_effect = error

        with self.assertRaisesRegexp(access_control.UnauthorizedAccess,
                                     "some error"):
            approval_checks.CheckApprovalRequest(approval_request)
def CheckClientLabels(client_id,
                      labels_whitelist=None,
                      labels_owners_whitelist=None,
                      token=None):
  """Checks a given client against labels/owners whitelists."""

  labels_whitelist = labels_whitelist or []
  labels_owners_whitelist = labels_owners_whitelist or []

  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 labels_whitelist and
          label.owner in labels_owners_whitelist):
        return

  raise access_control.UnauthorizedAccess(
      "Client %s doesn't have necessary labels." % utils.SmartStr(client_id))
示例#29
0
def CheckResponseStatus(response):
    """Catch error conditions from the response and raise them."""
    # Common case exit early.
    if response.status == rdf_data_store.DataStoreResponse.Status.OK:
        return response

    elif (response.status ==
          rdf_data_store.DataStoreResponse.Status.AUTHORIZATION_DENIED):
        raise access_control.UnauthorizedAccess(response.status_desc,
                                                response.failed_subject)

    elif response.status == rdf_data_store.DataStoreResponse.Status.TIMEOUT_ERROR:
        raise data_store.TimeoutError(response.status_desc)

    elif (response.status ==
          rdf_data_store.DataStoreResponse.Status.DATA_STORE_ERROR):
        raise data_store.Error(response.status_desc)

    raise data_store.Error("Unknown error %s" % response.status_desc)
示例#30
0
def CheckFlowCanBeStartedOnClient(flow_name):
    """Checks if flow can be started on a particular client.

  Only flows with a category can bestarted. 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 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)