Пример #1
0
    def get(self):
        google_projects = flask.request.args.get("google_project_ids")

        if not google_projects:
            return (
                "Getting service accounts is only supported with the "
                "google_project_ids query param at the moment.",
                400,
            )

        # if not monitor, we should assume google project ids and parse
        google_project_ids = [
            project_id.strip()
            for project_id in unquote(google_projects).split(",")
        ]

        # check if user has permission to get service accounts
        # for these projects
        user_id = current_token["sub"]
        authorized = is_user_member_of_all_google_projects(
            user_id, google_project_ids)

        if not authorized:
            return (
                "Could not determine if user is a member on all the "
                "provided Google project IDs.",
                403,
            )

        service_accounts = self._get_project_service_accounts(
            google_project_ids=google_project_ids)

        response = {"service_accounts": service_accounts}

        return response, 200
Пример #2
0
def _get_patched_service_account_error_status(id_, sa):
    """
    Get error status for attempting to patch given service account with access.

    Args:
        id_ (str): Google service account identifier to update
        sa (
            fence.resources.google.service_account.GoogleServiceAccountRegistration
        ): the service account object with its email, project_access, a google project,
           and optionally a user who is attempting to modify/add
    """
    # check if user has permission to update the service account
    authorized = is_user_member_of_all_google_projects(
        sa.user_id, [sa.google_project_id]
    )
    if not authorized:
        msg = (
            'User "{}" does not have permission to update the provided '
            'service account "{}".'.format(sa.user_id, id_)
        )
        raise Unauthorized(msg)

    error_response = _get_service_account_error_status(sa)

    return error_response
Пример #3
0
    def delete(self, id_):
        """
        Delete a service account

        Args:
            id_ (str): Google service account email to delete
        """
        user_id = current_token["sub"]

        service_account_email = get_service_account_email(id_)
        registered_service_account = get_registered_service_account_from_email(
            service_account_email)
        if not registered_service_account:
            raise NotFound(
                "Could not find a registered service account from given email {}"
                .format(service_account_email))

        google_project_id = registered_service_account.google_project_id

        # check if user has permission to delete the service account
        authorized = is_user_member_of_all_google_projects(
            user_id, [google_project_id])

        if not authorized:
            return (
                'User "{}" does not have permission to delete the provided '
                'service account "{}".'.format(user_id, id_),
                403,
            )

        return self._delete(id_)
Пример #4
0
    def check_validity(self, early_return=True, db=None, config=None):
        """
        Determine whether or not project is valid for registration. If
        early_return is False, this object will store information about the
        failure.

        Args:
            early_return (bool, optional): Description
        """
        google_project_number = get_google_project_number(
            self.google_project_id)
        has_access = bool(google_project_number)

        self.set("monitor_has_access", has_access)
        # always early return if we can't access the project
        if not has_access:
            return

        membership = get_google_project_membership(self.google_project_id)

        if self.user_id is not None:
            user_has_access = is_user_member_of_all_google_projects(
                self.user_id, [self.google_project_id],
                membership=membership,
                db=db)
            self.set("user_has_access", user_has_access)
            if not user_has_access:
                # always early return if user isn't a member on the project
                return

        parent_org = get_google_project_parent_org(self.google_project_id)
        valid_parent_org = True

        # if there is an org, let's remove whitelisted orgs and then check validity
        # again
        white_listed_google_parent_orgs = (
            config.get("WHITE_LISTED_GOOGLE_PARENT_ORGS") if config else None)

        if parent_org:
            valid_parent_org = is_org_whitelisted(
                parent_org,
                white_listed_google_parent_orgs=white_listed_google_parent_orgs,
            )

        self.set("valid_parent_org", valid_parent_org)

        if not valid_parent_org and early_return:
            return

        user_members = None
        service_account_members = []
        try:
            user_members, service_account_members = get_google_project_valid_users_and_service_accounts(
                self.google_project_id, membership=membership)
            self.set("valid_member_types", True)
        except Exception:
            self.set("valid_member_types", False)
            if early_return:
                return

        # if we have valid members, we can check if they exist in fence
        users_in_project = None
        if user_members is not None:
            try:
                users_in_project = get_users_from_google_members(user_members,
                                                                 db=db)
                self.set("members_exist_in_fence", True)
            except Exception:
                self.set("members_exist_in_fence", False)
                if early_return:
                    return

        # use a generic validityinfo object to hold all the service accounts
        # validity. then check all the service accounts. Top level will be
        # invalid if any service accounts are invalid
        new_service_account_validity = ValidityInfo()
        if self.new_service_account:
            service_account_validity_info = GoogleServiceAccountValidity(
                self.new_service_account, self.google_project_id,
                google_project_number)

            service_account_id = str(self.new_service_account)

            google_sa_domains = (
                config.get("GOOGLE_MANAGED_SERVICE_ACCOUNT_DOMAINS")
                if config else None)
            # we do NOT need to check the service account type and external access
            # for google-managed accounts.
            if is_google_managed_service_account(
                    service_account_id,
                    google_managed_service_account_domains=google_sa_domains,
            ):
                service_account_validity_info.check_validity(
                    early_return=early_return,
                    check_type_and_access=False,
                    config=config,
                )
            else:
                service_account_validity_info.check_validity(
                    early_return=early_return,
                    check_type_and_access=True,
                    config=config)

            # update project with error info from the service accounts
            new_service_account_validity.set(service_account_id,
                                             service_account_validity_info)

            if not service_account_validity_info and early_return:
                # if we need to return early for invalid SA, make sure to include
                # error details and invalidate the overall validity
                self.set("new_service_account", new_service_account_validity)
                return

        self.set("new_service_account", new_service_account_validity)

        service_accounts = get_service_account_ids_from_google_members(
            service_account_members)

        white_listed_service_accounts = (
            config.get("WHITE_LISTED_SERVICE_ACCOUNT_EMAILS")
            if config else None)
        app_creds_file = (config.get("GOOGLE_APPLICATION_CREDENTIALS")
                          if config else None)

        remove_white_listed_service_account_ids(
            service_accounts,
            app_creds_file=app_creds_file,
            white_listed_sa_emails=white_listed_service_accounts,
        )

        # use a generic validityinfo object to hold all the service accounts
        # validity. then check all the service accounts. Top level will be
        # invalid if any service accounts are invalid
        service_accounts_validity = ValidityInfo()
        for service_account in service_accounts:
            service_account_id = str(service_account)

            service_account_validity_info = GoogleServiceAccountValidity(
                service_account, self.google_project_id, google_project_number)

            google_sa_domains = (
                config.get("GOOGLE_MANAGED_SERVICE_ACCOUNT_DOMAINS")
                if config else None)
            # we do NOT need to check the service account type and external access
            # for google-managed accounts.
            if is_google_managed_service_account(
                    service_account_id,
                    google_managed_service_account_domains=google_sa_domains,
            ):
                service_account_validity_info.check_validity(
                    early_return=early_return,
                    check_type_and_access=False,
                    config=config,
                )
            else:
                service_account_validity_info.check_validity(
                    early_return=early_return,
                    check_type_and_access=True,
                    config=config)

            # update project with error info from the service accounts
            service_accounts_validity.set(service_account_id,
                                          service_account_validity_info)

            if not service_account_validity_info and early_return:
                # if we need to return early for invalid SA, make sure to include
                # error details and invalidate the overall validity
                self.set("service_accounts", service_accounts_validity)
                return

        self.set("service_accounts", service_accounts_validity)

        # get the service accounts for the project to determine all the data
        # the project can access through the service accounts
        service_accounts = get_registered_service_accounts(
            self.google_project_id, db=db)
        service_account_project_access = get_project_access_from_service_accounts(
            service_accounts, db=db)

        # use a generic validityinfo object to hold all the projects validity
        project_access_validities = ValidityInfo()

        # extend list with any provided access to test
        for provided_access in self.new_service_account_access:
            project = get_project_from_auth_id(provided_access)

            # if provided access doesn't exist, set error in project_validity
            if not project:
                project_validity = ValidityInfo()
                project_validity.set("exists", False)
                project_validity.set("all_users_have_access", None)
                project_access_validities.set(str(provided_access),
                                              project_validity)
            else:
                service_account_project_access.append(project)

        # make sure all the users of the project actually have access to all
        # the data the service accounts have access to
        for project in service_account_project_access:
            project_validity = ValidityInfo()
            project_validity.set("exists", True)

            # if all the users exist in our db, we can check if they have valid
            # access
            valid_access = None
            if users_in_project:
                valid_access = do_all_users_have_access_to_project(
                    users_in_project, project.id, db=db)
            project_validity.set("all_users_have_access", valid_access)

            project_access_validities.set(str(project.auth_id),
                                          project_validity)

        self.set("access", project_access_validities)
        return