예제 #1
0
def test_invalid_google_project_membership(valid_google_project_patcher):
    """
    Test that when the Google Project is invalid, the resulting
    GoogleProjectValidity is False-y and contains the expected information.

    Here we're testing when the Google Project has invalid membership.
    """
    patcher = valid_google_project_patcher
    patcher[
        "get_google_project_valid_users_and_service_accounts"].side_effect = Exception(
        )

    google_project_validity = GoogleProjectValidity("some-project-id")

    # should evaluate to true by default before checking validity
    assert google_project_validity

    google_project_validity.check_validity(early_return=False)

    # should evaluate to false since invalid
    assert not google_project_validity

    # test that it contains the correct error information
    assert "valid_parent_org" in google_project_validity
    assert google_project_validity["valid_parent_org"]

    assert "valid_member_types" in google_project_validity
    assert not google_project_validity["valid_member_types"]

    assert "members_exist_in_fence" in google_project_validity
    assert not google_project_validity["members_exist_in_fence"]
예제 #2
0
def test_valid_google_project(valid_google_project_patcher):
    """
    Test that when everything is valid, the GoogleProjectValidity is valid
    and has the expected information.
    """
    google_project_validity = GoogleProjectValidity("some-project-id")

    # should evaluate to true by default
    assert google_project_validity

    google_project_validity.check_validity(early_return=False)

    # should evaluate to true since all checks should result in valid project
    assert google_project_validity

    # test that it contains the default error information and it's true
    assert "valid_parent_org" in google_project_validity
    assert google_project_validity["valid_parent_org"]

    assert "valid_member_types" in google_project_validity
    assert google_project_validity["valid_member_types"]

    assert "members_exist_in_fence" in google_project_validity
    assert google_project_validity["members_exist_in_fence"]

    assert "new_service_account" in google_project_validity
    assert "service_accounts" in google_project_validity
    assert "access" in google_project_validity
예제 #3
0
def test_invalid_google_project_no_monitor(valid_google_project_patcher):
    """
    Test that when we can't determine the project number, we determine
    that the project is invalid. This happens when the monitoring service account
    does not have access on the project
    """
    patcher = valid_google_project_patcher
    patcher["get_google_project_number"].return_value = None

    google_project_validity = GoogleProjectValidity("some-project-id")

    # should evaluate to true by default before checking validity
    assert google_project_validity

    google_project_validity.check_validity(early_return=False)

    # should evaluate to false since invalid
    assert not google_project_validity

    # test that it contains the correct error information
    assert "valid_parent_org" in google_project_validity
    assert not google_project_validity["valid_parent_org"]

    assert "valid_member_types" in google_project_validity
    assert not google_project_validity["valid_member_types"]

    assert "members_exist_in_fence" in google_project_validity
    assert not google_project_validity["members_exist_in_fence"]

    assert "new_service_account" in google_project_validity
    assert "service_accounts" in google_project_validity
    assert "access" in google_project_validity
예제 #4
0
def test_invalid_google_project_parent_org(app, valid_google_project_patcher):
    """
    Test that when the Google Project is invalid, the resulting
    GoogleProjectValidity is False-y and contains the expected information.

    Here we're testing when the Google Project has a parent org (which is
    invalid).
    """
    patcher = valid_google_project_patcher
    patcher["get_google_project_parent_org"].return_value = "some-parent-org"

    google_project_validity = GoogleProjectValidity("some-project-id")

    # should evaluate to true by default before checking validity
    assert google_project_validity

    google_project_validity.check_validity(early_return=False)

    # should evaluate to false since invalid
    assert not google_project_validity

    # test that it contains the correct error information
    assert "valid_parent_org" in google_project_validity
    assert not google_project_validity["valid_parent_org"]

    assert "valid_member_types" in google_project_validity
    assert google_project_validity["valid_member_types"]

    assert "members_exist_in_fence" in google_project_validity
    assert google_project_validity["members_exist_in_fence"]

    assert "new_service_account" in google_project_validity
    assert "service_accounts" in google_project_validity
    assert "access" in google_project_validity
예제 #5
0
def test_valid_google_project_access(valid_google_project_patcher,
                                     valid_service_account_patcher,
                                     db_session):
    """
    Test that when everything is valid and there are access to data through
    projects (access is all valid), the GoogleProjectValidity is valid
    and has the expected information.
    """
    patcher = valid_google_project_patcher

    project1 = Project(auth_id="some-project-auth-id")
    project2 = Project(auth_id="some-other-project-auth-id")
    db_session.add(project1)
    db_session.add(project2)
    db_session.commit()

    patcher["get_project_access_from_service_accounts"].return_value = [
        project1,
        project2,
    ]

    google_project_validity = GoogleProjectValidity("some-project-id")

    # should evaluate to true by default before checking validity
    assert google_project_validity

    google_project_validity.check_validity(early_return=False)

    # should evaluate to true since it's valid
    assert google_project_validity

    # test that it contains the correct error information
    assert "valid_parent_org" in google_project_validity
    assert google_project_validity["valid_parent_org"]

    assert "valid_member_types" in google_project_validity
    assert google_project_validity["valid_member_types"]

    assert "members_exist_in_fence" in google_project_validity
    assert google_project_validity["members_exist_in_fence"]

    assert "new_service_account" in google_project_validity
    assert "service_accounts" in google_project_validity
    assert "access" in google_project_validity
    assert hasattr(google_project_validity["access"], "__iter__")
    assert "some-project-auth-id" in (google_project_validity["access"])
    assert "some-other-project-auth-id" in (google_project_validity["access"])
예제 #6
0
def test_invalid_google_project_access(valid_google_project_patcher,
                                       db_session):
    """
    Test that when the Google Project is invalid, the resulting
    GoogleProjectValidity is False-y and contains the expected information.

    Here we're testing when the Google Project's members have invalid access.
    """
    patcher = valid_google_project_patcher

    project = Project(auth_id="some-project-auth-id")
    db_session.add(project)
    db_session.commit()

    patcher["get_project_access_from_service_accounts"].return_value = [
        project
    ]
    patcher["get_users_from_google_members"].return_value = ["test-user"]
    patcher["do_all_users_have_access_to_project"].return_value = False

    google_project_validity = GoogleProjectValidity("some-project-id")

    # should evaluate to true by default before checking validity
    assert google_project_validity

    google_project_validity.check_validity(early_return=False)

    # should evaluate to false since invalid
    assert not google_project_validity

    # test that it contains the correct error information
    assert "valid_parent_org" in google_project_validity
    assert google_project_validity["valid_parent_org"]

    assert "valid_member_types" in google_project_validity
    assert google_project_validity["valid_member_types"]

    assert "members_exist_in_fence" in google_project_validity
    assert google_project_validity["members_exist_in_fence"]

    assert "new_service_account" in google_project_validity
    assert "service_accounts" in google_project_validity
    assert "access" in google_project_validity
    assert hasattr(google_project_validity["access"], "__iter__")
    assert "some-project-auth-id" in (google_project_validity["access"])
    assert not google_project_validity["access"]["some-project-auth-id"]
예제 #7
0
def _is_valid_google_project(google_project_id, db=None, config=None):
    """
    Validate the given google project id and remove all registered service
    accounts under that project if invalid.
    """
    try:
        project_validity = GoogleProjectValidity(google_project_id)
        project_validity.check_validity(early_return=True, db=db, config=config)

    except Exception:
        # any issues, assume invalid
        # TODO not sure if this is the right way to handle this...
        print("Project determined invalid due to unhandled exception:")
        traceback.print_exc()
        project_validity = None

    return project_validity
예제 #8
0
def _is_valid_google_project(google_project_id, db=None):
    """
    Validate the given google project id and remove all registered service
    accounts under that project if invalid.
    """
    try:
        project_validity = GoogleProjectValidity(google_project_id)
        project_validity.check_validity(early_return=True, db=db)
    except Exception as exc:
        # any issues, assume invalid
        # TODO not sure if this is the right way to handle this...
        logger.warning(
            "Project {} determined invalid due to unhandled exception: {}. "
            "Assuming project is invalid.".format(google_project_id, str(exc)))
        traceback.print_exc()
        project_validity = None

    return project_validity
예제 #9
0
def test_valid_google_project_service_accounts(app,
                                               valid_google_project_patcher,
                                               valid_service_account_patcher):
    """
    Test that when everything is valid and there are service accounts (which
    are also all valid), the GoogleProjectValidity is valid
    and has the expected information.
    """
    patcher = valid_google_project_patcher

    patcher["get_service_account_ids_from_google_members"].return_value = [
        "some-account-id",
        "some-other-account-id",
    ]

    google_project_validity = GoogleProjectValidity("some-project-id")

    # should evaluate to true by default before checking validity
    assert google_project_validity

    google_project_validity.check_validity(early_return=False)

    # should evaluate to true since it's valid
    assert google_project_validity

    # test that it contains the correct error information
    assert "valid_parent_org" in google_project_validity
    assert google_project_validity["valid_parent_org"]

    assert "valid_member_types" in google_project_validity
    assert google_project_validity["valid_member_types"]

    assert "members_exist_in_fence" in google_project_validity
    assert google_project_validity["members_exist_in_fence"]

    assert "new_service_account" in google_project_validity
    assert "service_accounts" in google_project_validity
    assert hasattr(google_project_validity["service_accounts"], "__iter__")
    assert "some-account-id" in (google_project_validity["service_accounts"])
    assert "some-other-account-id" in (
        google_project_validity["service_accounts"])

    assert "access" in google_project_validity
예제 #10
0
def _get_service_account_error_status(sa):
    """
    Get a dictionary describing any errors that will occur if attempting
    to give service account specified permissions fails.

    Args:
        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

    Returns:
        dict: error information if unsuccessful, { "success": True } otherwise

        Example:
        {
            "success": False,
            "errors": {
                "service_account_email": {
                    "status": 200,
                    "error": None,
                    "error_description": None
                },
                "google_project_id": {
                    "status": 200,
                    "error": None,
                    "error_description": None
                },
                "project_access": {
                    "projectA": {
                        "status": 200,
                        "error": None,
                        "error_description": None
                    },
                    "projectB": {
                        "status": 403,
                        "error": "unauthorized",
                        "error_description": "Not all users have access requested"
                    }
                },
                "expires_in": {
                    "status": 400,
                    "error": "user_error",
                    "error_description": "expires_in must be a positive integer"
                }
            }
        }
    """
    response = {
        "success": False,
        "errors": {
            "service_account_email": None,
            "google_project_id": None,
            "project_access": None,
            "expires_in": {
                "status": 200,
                "error": None,
                "error_description": None
            },
        },
    }

    try:
        get_valid_expiration_from_request()
    except UserError as e:
        response["errors"]["expires_in"] = {
            "status": e.code,
            "error": "user_error",
            "error_description": e.message,
        }

    project_validity = GoogleProjectValidity(
        google_project_id=sa.google_project_id,
        new_service_account=sa.email,
        new_service_account_access=sa.project_access,
        user_id=sa.user_id,
    )
    project_validity.check_validity(early_return=False)

    response["errors"][
        "google_project_id"] = _get_google_project_id_error_status(
            project_validity)

    response["errors"][
        "service_account_email"] = _get_service_account_email_error_status(
            project_validity)

    response["errors"]["project_access"] = _get_project_access_error_status(
        project_validity)

    # if we cannot find the monitoring service account, the other checks statuses should
    # not be 200 and should be populated with relevant information
    if (response["errors"]["google_project_id"]["error"] ==
            ValidationErrors.MONITOR_NOT_FOUND):
        if response["errors"]["service_account_email"].get("status") == 200:
            response["errors"]["service_account_email"]["status"] = 400
            response["errors"]["service_account_email"][
                "error"] = ValidationErrors.MONITOR_NOT_FOUND
            response["errors"]["service_account_email"]["error_description"] = (
                "Fence's monitoring service account was not found on the project so we "
                "were unable to complete the necessary validation checks.")
        if response["errors"]["project_access"].get("status") == 200:
            response["errors"]["project_access"]["status"] = 400
            response["errors"]["project_access"][
                "error"] = ValidationErrors.MONITOR_NOT_FOUND
            response["errors"]["project_access"]["error_description"] = (
                "Fence's monitoring service account was not found on the project so we "
                "were unable to complete the necessary validation checks.")

    # all statuses must be 200 to be successful
    if (response["errors"]["service_account_email"].get("status") == 200
            and response["errors"]["google_project_id"].get("status") == 200
            and response["errors"]["project_access"].get("status") == 200
            and response["errors"]["expires_in"].get("status") == 200):
        response["success"] = True

    return response
예제 #11
0
def _get_service_account_error_status(sa):
    """
    Get a dictionary describing any errors that will occur if attempting
    to give service account specified permissions fails.

    Args:
        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

    Returns:
        dict: error information if unsuccessful, { "success": True } otherwise

        Example:
        {
            "success": False,
            "errors": {
                "service_account_email": {
                    "status": 200,
                    "error": None,
                    "error_description": None
                },
                "google_project_id": {
                    "status": 200,
                    "error": None,
                    "error_description": None
                },
                "project_access": {
                    "projectA": {
                        "status": 200,
                        "error": None,
                        "error_description": None
                    },
                    "projectB": {
                        "status": 403,
                        "error": "unauthorized",
                        "error_description": "Not all users have access requested"
                    }
                }
            }
        }
    """
    response = {
        "success": False,
        "errors": {
            "service_account_email": None,
            "google_project_id": None,
            "project_access": None,
        },
    }

    project_validity = GoogleProjectValidity(
        google_project_id=sa.google_project_id,
        new_service_account=sa.email,
        new_service_account_access=sa.project_access,
        user_id=sa.user_id,
    )
    project_validity.check_validity(early_return=False)

    response["errors"][
        "service_account_email"] = _get_service_account_email_error_status(
            project_validity)

    response["errors"][
        "google_project_id"] = _get_google_project_id_error_status(
            project_validity)

    response["errors"]["project_access"] = _get_project_access_error_status(
        project_validity)

    # all statuses must be 200 to be successful
    if (response["errors"]["service_account_email"].get("status") == 200
            and response["errors"]["google_project_id"].get("status") == 200
            and response["errors"]["project_access"].get("status") == 200):
        response["success"] = True

    return response