Exemplo n.º 1
0
def test_get_valid_service_account_id_for_client(client_id, prefix):
    """
    Test that even when client id starts with a number, we can
    get a valid name
    """
    user_id = 54
    result = get_valid_service_account_id_for_client(client_id, user_id, prefix=prefix)
    assert prefix in result
    assert str(user_id) in result
    assert len(result) > 6
    assert len(result) <= 30
Exemplo n.º 2
0
def create_service_account(client_id, user_id, username, proxy_group_id):
    """
    Create a Google Service account for the current client and user.

    Args:
        g_cloud_manager (cirrus.GoogleCloudManager): instance of
        cloud manager to use

    Returns:
        fence.models.GoogleServiceAccount: New service account
    """
    if proxy_group_id:
        if client_id:
            service_account_id = get_valid_service_account_id_for_client(
                client_id, user_id)
        else:
            service_account_id = get_valid_service_account_id_for_user(
                user_id, username)

        with GoogleCloudManager() as g_cloud:
            new_service_account = g_cloud.create_service_account_for_proxy_group(
                proxy_group_id, account_id=service_account_id)

        service_account = GoogleServiceAccount(
            google_unique_id=new_service_account["uniqueId"],
            client_id=client_id,
            user_id=user_id,
            email=new_service_account["email"],
            google_project_id=new_service_account["projectId"],
        )

        current_session.add(service_account)
        current_session.commit()

        flask.current_app.logger.info(
            "Created service account {} for proxy group {}.".format(
                new_service_account["email"], proxy_group_id))

        return service_account
    else:
        flask.abort(
            404,
            "Could not find Google proxy group for current user in the "
            "given token.",
        )
Exemplo n.º 3
0
def get_or_create_service_account(client_id, user_id, username,
                                  proxy_group_id):
    """
    Create a Google Service account for the current client and user.
    This effectively handles conflicts in Google and will update our db
    accordingly based on the newest information from Google.

    Args:
        g_cloud_manager (cirrus.GoogleCloudManager): instance of
        cloud manager to use

    Returns:
        fence.models.GoogleServiceAccount: New service account
    """
    if proxy_group_id:
        if client_id:
            service_account_id = get_valid_service_account_id_for_client(
                client_id,
                user_id,
                prefix=config["GOOGLE_SERVICE_ACCOUNT_PREFIX"])
        else:
            service_account_id = get_valid_service_account_id_for_user(
                user_id,
                username,
                prefix=config["GOOGLE_SERVICE_ACCOUNT_PREFIX"])

        with GoogleCloudManager() as g_cloud:
            new_service_account = g_cloud.create_service_account_for_proxy_group(
                proxy_group_id, account_id=service_account_id)

        return _update_service_account_db_entry(client_id, user_id,
                                                proxy_group_id,
                                                new_service_account)
    else:
        flask.abort(
            404,
            "Could not find Google proxy group for current user in the given token.",
        )
Exemplo n.º 4
0
def _update_service_account_db_entry(
    client_id, user_id, proxy_group_id, new_service_account
):
    """
    Now that SA exists in Google so lets check our db and update/add as necessary
    """

    # if we're now using a prefix for SAs, cleanup the db
    if config["GOOGLE_SERVICE_ACCOUNT_PREFIX"]:
        # - if using the old naming convention without a prefix,
        # remove that SA from the db b/c we'll be using the new one from now on
        # - construct old email using account id provided and
        # domain from new email to find the db entry
        old_service_account_id = get_valid_service_account_id_for_client(
            client_id, user_id
        )
        old_sa_email = "@".join(
            (old_service_account_id, new_service_account["email"].split("@")[-1])
        )

        # clear out old SA and keys if there is one
        old_service_account_db_entry = (
            current_session.query(GoogleServiceAccount)
            .filter(GoogleServiceAccount.email == old_sa_email)
            .first()
        )
        if old_service_account_db_entry:
            logger.info(
                "Found Google Service Account using old naming convention without a prefix: "
                "{}. Removing from db. Keys should still have access in Google until "
                "cronjob removes them (e.g. fence-create google-manage-keys). NOTE: "
                "the SA will still exist in Google but fence will use new SA {} for "
                "new keys.".format(old_sa_email, new_service_account["email"])
            )

            old_service_account_keys_db_entries = (
                current_session.query(GoogleServiceAccountKey)
                .filter(
                    GoogleServiceAccountKey.service_account_id
                    == old_service_account_db_entry.id
                )
                .all()
            )

            # remove the keys then the sa itself from db
            for old_key in old_service_account_keys_db_entries:
                current_session.delete(old_key)

            current_session.commit()
            current_session.delete(old_service_account_db_entry)

    service_account_db_entry = (
        current_session.query(GoogleServiceAccount)
        .filter(GoogleServiceAccount.email == new_service_account["email"])
        .first()
    )

    if not service_account_db_entry:
        service_account_db_entry = GoogleServiceAccount(
            google_unique_id=new_service_account["uniqueId"],
            client_id=client_id,
            user_id=user_id,
            email=new_service_account["email"],
            google_project_id=new_service_account["projectId"],
        )
        current_session.add(service_account_db_entry)
    else:
        service_account_db_entry.google_unique_id = new_service_account["uniqueId"]
        service_account_db_entry.email = new_service_account["email"]
        service_account_db_entry.google_project_id = (new_service_account["projectId"],)

    current_session.commit()

    logger.info(
        "Created service account {} for proxy group {}.".format(
            new_service_account["email"], proxy_group_id
        )
    )

    return service_account_db_entry
Exemplo n.º 5
0
def get_service_account(client_id, user_id, username):
    """
    Return the service account (from Fence db) for given client.

    Get the service account that is associated with the given client
    for this user. There will be a single service account per client.

    NOTE: The user themselves have a "primary" service account which you
          can retrieve by passing in `None` as the client_id.

    Returns:
        fence.models.GoogleServiceAccount: Client's service account
    """
    service_accounts = (
        current_session.query(GoogleServiceAccount)
        .filter_by(client_id=client_id, user_id=user_id)
        .all()
    )
    if len(service_accounts) == 1:
        return service_accounts[0]

    # in rare cases there's a possible that 2 SA's exist for 1 user that haven't
    # been cleaned up yet. This happens when a users username is changed. To ensure
    # getting the newest SA, we need to check for the SA ID based off the current
    # username
    service_account = None

    # determine expected SA name based off username
    if client_id:
        service_account_id = get_valid_service_account_id_for_client(
            client_id, user_id, prefix=config["GOOGLE_SERVICE_ACCOUNT_PREFIX"]
        )
    else:
        service_account_id = get_valid_service_account_id_for_user(
            user_id, username, prefix=config["GOOGLE_SERVICE_ACCOUNT_PREFIX"]
        )

    for sa in service_accounts:
        if service_account_id in sa.email:
            service_account = sa
        else:
            logger.info(
                "Found Google Service Account using invalid/old name: "
                "{}. Removing from db. Keys should still have access in Google until "
                "cronjob removes them (e.g. fence-create google-manage-keys). NOTE: "
                "the SA will still exist in Google but fence will use new SA {} for "
                "new keys.".format(sa.email, service_account_id)
            )

            old_service_account_keys_db_entries = (
                current_session.query(GoogleServiceAccountKey)
                .filter(GoogleServiceAccountKey.service_account_id == sa.id)
                .all()
            )

            # remove the keys then the sa itself from db
            for old_key in old_service_account_keys_db_entries:
                current_session.delete(old_key)

            # commit the deletion of keys first, then do SA deletion
            current_session.commit()
            current_session.delete(sa)
            current_session.commit()

    return service_account