def test_delete_expired_service_account_keys_both_user_and_client(
        cloud_manager, app, db_session, test_user_a, oauth_client):
    """
    Test deleting all expired service account keys
    """
    import fence

    fence.settings = MagicMock()
    cloud_manager.return_value.__enter__.return_value.delete_service_account_key.return_value = (
        {})

    current_time = int(time.time())

    service_account = GoogleServiceAccount(
        google_unique_id="1",
        user_id=test_user_a["user_id"],
        google_project_id="test",
        email="*****@*****.**",
    )
    client_service_account = GoogleServiceAccount(
        google_unique_id="1",
        user_id=test_user_a["user_id"],
        client_id=oauth_client["client_id"],
        google_project_id="test",
        email="*****@*****.**",
    )
    db_session.add(service_account)
    db_session.add(client_service_account)
    db_session.commit()

    # Add 2 expired and 1 not expired accounts
    service_account_key1 = GoogleServiceAccountKey(
        key_id=1,
        service_account_id=service_account.id,
        expires=current_time - 3600)
    service_account_key2 = GoogleServiceAccountKey(
        key_id=2,
        service_account_id=client_service_account.id,
        expires=current_time - 3600,
    )
    service_account_key3 = GoogleServiceAccountKey(
        key_id=3,
        service_account_id=service_account.id,
        expires=current_time + 3600)

    db_session.add(service_account_key1)
    db_session.add(service_account_key2)
    db_session.add(service_account_key3)
    db_session.commit()

    records = db_session.query(GoogleServiceAccountKey).all()
    assert len(records) == 3

    # call function to delete expired service account
    remove_expired_google_service_account_keys(config["DB"])
    # check database. Expect 2 deleted
    records = db_session.query(GoogleServiceAccountKey).all()
    assert len(records) == 1
    assert records[0].id == service_account_key3.id
Example #2
0
def test_google_delete_owned_access_token(
    app, client, oauth_client, cloud_manager, db_session, encoded_creds_jwt
):
    """
    Test ``DELETE /credentials/google``.
    """
    encoded_credentials_jwt = encoded_creds_jwt["jwt"]
    user_id = encoded_creds_jwt["user_id"]
    client_id = encoded_creds_jwt["client_id"]

    service_account_key = "some_key_321"
    service_account_id = "123456789"
    path = "/credentials/google/" + service_account_key

    def get_account_keys(*args, **kwargs):
        # Return the keys only if the correct account is given
        if args[0] == service_account_id:
            # Return two keys, first one is NOT the one we're
            # requesting to delete
            return [
                {"name": "project/service_accounts/keys/over_9000"},
                {"name": "project/service_accounts/keys/" + service_account_key},
            ]
        else:
            return []

    (
        cloud_manager.return_value.__enter__.return_value.get_service_account_keys_info.side_effect
    ) = get_account_keys

    # create a service account for client for user
    service_account = GoogleServiceAccount(
        google_unique_id=service_account_id,
        client_id=client_id,
        user_id=user_id,
        email=(client_id + "-" + str(user_id) + "@test.com"),
        google_project_id="projectId-0",
    )
    db_session.add(service_account)
    db_session.commit()

    response = client.delete(
        path, data={}, headers={"Authorization": "Bearer " + encoded_credentials_jwt}
    )

    # check that the service account id was included in a call to
    # cloud_manager
    assert any(
        [
            str(mock_call)
            for mock_call in cloud_manager.mock_calls
            if service_account_id in str(mock_call)
        ]
    )
    assert response.status_code == 204

    # check that we actually requested to delete the correct service key
    (
        cloud_manager.return_value.__enter__.return_value.delete_service_account_key
    ).assert_called_with(service_account_id, service_account_key)
Example #3
0
def test_client_delete_error(app, db_session, cloud_manager, test_user_a):
    """
    Test that when Google gives us an error when deleting the service account,
    we don't remove it from the db.
    """
    client_name = "test123"
    client = Client(client_id=client_name, client_secret="secret", name=client_name)
    db_session.add(client)
    db_session.commit()

    client_service_account = GoogleServiceAccount(
        google_unique_id="jf09238ufposijf",
        client_id=client.client_id,
        user_id=test_user_a["user_id"],
        google_project_id="test",
        email="*****@*****.**",
    )
    db_session.add(client_service_account)
    db_session.commit()

    # error when deleting service account
    (
        cloud_manager.return_value.__enter__.return_value.delete_service_account.return_value
    ) = {"error": "something bad happened"}

    delete_client_action(config["DB"], client_name)

    client_after = db_session.query(Client).filter_by(name=client_name).all()
    client_service_account_after = (
        db_session.query(GoogleServiceAccount).filter_by(client_id=client.client_id)
    ).all()

    # make sure client is deleted but service account we couldn't delete stays
    assert len(client_after) == 0
    assert len(client_service_account_after) == 1
Example #4
0
def test_client_delete(app, db_session, cloud_manager, test_user_a):
    """
    Test that the client delete function correctly cleans up the client's
    service accounts and the client themself.
    """
    client_name = "test123"
    client = Client(client_id=client_name,
                    client_secret="secret",
                    name=client_name)
    db_session.add(client)
    db_session.commit()

    client_service_account = GoogleServiceAccount(
        google_unique_id="jf09238ufposijf",
        client_id=client.client_id,
        user_id=test_user_a["user_id"],
        google_project_id="test",
        email="*****@*****.**",
    )
    db_session.add(client_service_account)
    db_session.commit()

    # empty return means success
    (cloud_manager.return_value.__enter__.return_value.delete_service_account.
     return_value) = {}

    delete_client_action(app.config["DB"], client_name)

    client_after = db_session.query(Client).filter_by(name=client_name).all()
    client_service_account_after = (
        db_session.query(GoogleServiceAccount).filter_by(
            client_id=client.client_id)).all()
    assert len(client_after) == 0
    assert len(client_service_account_after) == 0
Example #5
0
def test_google_bucket_access_existing_proxy_group(
    app,
    google_storage_client_mocker,
    client,
    cloud_manager,
    db_session,
    encoded_creds_jwt,
    monkeypatch,
):
    monkeypatch.setitem(app.config, "MOCK_AUTH", False)

    user_id = encoded_creds_jwt["user_id"]
    client_id = encoded_creds_jwt["client_id"]

    service_account_id = "123456789"
    path = "/credentials/google/"

    proj = Project(id=129, name="test_proj")
    ap = AccessPrivilege(
        user_id=user_id, project_id=proj.id, privilege=["write-storage"]
    )
    cloud = CloudProvider(id=129, name="google")
    bucket = Bucket(id=129, provider_id=cloud.id)
    gbag = GoogleBucketAccessGroup(
        id=129, bucket_id=bucket.id, email="*****@*****.**", privileges=["write"]
    )
    ptob = ProjectToBucket(id=129, project_id=proj.id, bucket_id=bucket.id)
    sa = StorageAccess(project_id=proj.id, provider_id=cloud.id)
    service_account = GoogleServiceAccount(
        google_unique_id=service_account_id,
        client_id=client_id,
        user_id=user_id,
        email=(client_id + "-" + str(user_id) + "@test.com"),
        google_project_id="projectId-0",
    )

    db_session.add(service_account)
    db_session.commit()
    db_session.add(proj)
    db_session.add(ap)
    db_session.add(cloud)
    db_session.add(bucket)
    db_session.add(gbag)
    db_session.add(ptob)
    db_session.add(sa)
    db_session.add(service_account)
    db_session.commit()

    encoded_credentials_jwt = encoded_creds_jwt["jwt"]

    path = "/credentials/google/"
    data = {}

    response = client.post(
        path, data=data, headers={"Authorization": "Bearer " + encoded_credentials_jwt}
    )

    assert google_storage_client_mocker.add_bucket_acl.called is False
    assert response.status_code == 200
Example #6
0
def test_google_delete_invalid_access_token(app, client, oauth_client,
                                            cloud_manager, db_session):
    """
    Test ``DELETE /credentials/google``.
    """
    client_id = oauth_client["client_id"]
    service_account_key = "some_key_321"
    service_account_id = "123456789"
    proxy_group_id = "proxy_group_0"
    path = ("/credentials/google/" + service_account_key + "/")

    def get_account_keys(*args, **kwargs):
        # Return the keys only if the correct account is given
        if args[0] == service_account_id:
            # Return two keys, NEITHER are the key we want to delete
            return [{
                "name": "project/service_accounts/keys/voyager"
            }, {
                "name": "project/service_accounts/keys/deep-space-nine"
            }]
        else:
            return []

    (cloud_manager.return_value.__enter__.return_value.
     get_service_account_keys_info.side_effect) = get_account_keys

    with app.test_client() as app_client:

        # set global client context
        flask.g.client_id = client_id

        # get test user info
        user = (db_session.query(User).filter_by(username="******").first())
        user_id = user.id

        # create a  proxy group for user
        proxy_group = GoogleProxyGroup(
            id=proxy_group_id,
            user_id=user_id,
        )
        db_session.add(proxy_group)

        # create a service account for client for user
        service_account = GoogleServiceAccount(
            google_unique_id=service_account_id,
            client_id=client_id,
            user_id=user_id,
            email=(client_id + "-" + str(user_id) + "@test.com"))
        db_session.add(user)
        db_session.add(service_account)
        db_session.commit()

        response = app_client.delete(path, data={})

        # check that we didn't try to delete, since the key doesn't exist
        assert (cloud_manager.return_value.__enter__.return_value.
                delete_service_account_key).called is False

        assert response.status_code == 404
Example #7
0
def test_google_delete_invalid_access_token(
    app, client, oauth_client, cloud_manager, db_session, encoded_creds_jwt
):
    """
    Test ``DELETE /credentials/google``.
    """
    encoded_credentials_jwt = encoded_creds_jwt["jwt"]
    user_id = encoded_creds_jwt["user_id"]
    client_id = encoded_creds_jwt["client_id"]

    service_account_key = "some_key_321"
    service_account_id = "123456789"
    path = "/credentials/google/" + service_account_key + "/"

    def get_account_keys(*args, **kwargs):
        # Return the keys only if the correct account is given
        if args[0] == service_account_id:
            # Return two keys, NEITHER are the key we want to delete
            return [
                {"name": "project/service_accounts/keys/voyager"},
                {"name": "project/service_accounts/keys/deep-space-nine"},
            ]
        else:
            return []

    (
        cloud_manager.return_value.__enter__.return_value.get_service_account_keys_info.side_effect
    ) = get_account_keys

    # create a service account for client for user
    service_account = GoogleServiceAccount(
        google_unique_id=service_account_id,
        client_id=client_id,
        user_id=user_id,
        email=(client_id + "-" + str(user_id) + "@test.com"),
        google_project_id="projectId-0",
    )
    db_session.add(service_account)
    db_session.commit()

    # make function return the service account we created and don't try to update db
    # since we already did it in the test
    mock = MagicMock()
    mock.return_value = service_account
    patch("fence.resources.google.utils.get_or_create_service_account", mock).start()
    patch("fence.resources.google.utils._update_service_account_db_entry", mock).start()

    response = client.delete(
        path, data={}, headers={"Authorization": "Bearer " + encoded_credentials_jwt}
    )

    # check that we didn't try to delete, since the key doesn't exist
    assert (
        cloud_manager.return_value.__enter__.return_value.delete_service_account_key
    ).called is False

    assert response.status_code == 404
Example #8
0
def test_google_attempt_delete_unowned_access_token(app, client, oauth_client,
                                                    cloud_manager, db_session):
    """
    Test ``DELETE /credentials/google``.
    """
    client_id = oauth_client["client_id"]
    service_account_key = "some_key_321"
    proxy_group_id = "proxy_group_0"
    path = ("/credentials/google/" + service_account_key + "/")

    with app.test_client() as app_client:

        # set global client context
        flask.g.client_id = client_id

        # get test user info
        user = (db_session.query(User).filter_by(username="******").first())
        user_id = user.id

        # create a  proxy group for user
        proxy_group = GoogleProxyGroup(
            id=proxy_group_id,
            user_id=user_id,
        )
        db_session.add(proxy_group)

        # create a service account for A DIFFERENT CLIENT
        client = Client(
            client_id="NOT_THIS_GUY",
            client_secret="a0987u23on192y",
            name="NOT_THIS_GUY",
        )
        service_account = GoogleServiceAccount(
            google_unique_id="123456789",
            client_id="NOT_THIS_GUY",
            user_id=user_id,
            email=("NOT_THIS_GUY" + "-" + str(user_id) + "@test.com"))
        db_session.add(user)
        db_session.add(client)
        db_session.add(service_account)
        db_session.commit()

        response = app_client.delete(path, data={})

        # check that we didn't try to get key info or delete,
        # since the current user/client doesn't have the key
        assert (cloud_manager.return_value.__enter__.return_value.
                get_service_account_keys_info).called is False

        assert (cloud_manager.return_value.__enter__.return_value.
                delete_service_account_key).called is False

        assert response.status_code == 404
Example #9
0
def test_google_attempt_delete_unowned_access_token(app, client, oauth_client,
                                                    cloud_manager, db_session,
                                                    encoded_creds_jwt):
    """
    Test ``DELETE /credentials/google``.
    """
    encoded_credentials_jwt = encoded_creds_jwt["jwt"]
    user_id = encoded_creds_jwt["user_id"]

    service_account_key = "some_key_321"
    path = "/credentials/google/" + service_account_key + "/"

    # create a service account for A DIFFERENT CLIENT
    client_entry = Client(client_id="NOT_THIS_GUY",
                          client_secret="a0987u23on192y",
                          name="NOT_THIS_GUY")
    service_account = GoogleServiceAccount(
        google_unique_id="123456789",
        client_id="NOT_THIS_GUY",
        user_id=user_id,
        email=("NOT_THIS_GUY" + "-" + str(user_id) + "@test.com"),
        google_project_id="projectId-0",
    )
    db_session.add(client_entry)
    db_session.add(service_account)
    db_session.commit()

    # make function return the service account we created and don't try to update db
    # since we already did it in the test
    mock = MagicMock()
    mock.return_value = service_account
    patch("fence.resources.google.utils.get_or_create_service_account",
          mock).start()
    patch("fence.resources.google.utils._update_service_account_db_entry",
          mock).start()

    response = client.delete(
        path,
        data={},
        headers={"Authorization": "Bearer " + encoded_credentials_jwt})

    # check that we didn't try to get key info or delete,
    # since the current user/client doesn't have the key
    assert (cloud_manager.return_value.__enter__.return_value.
            get_service_account_keys_info).called is False

    assert (cloud_manager.return_value.__enter__.return_value.
            delete_service_account_key).called is False

    assert response.status_code == 404
Example #10
0
def test_google_create_access_token_post(app, client, oauth_client,
                                         cloud_manager, db_session,
                                         encoded_creds_jwt):
    """
    Test ``POST /credentials/google`` gets a new access key.
    """
    encoded_credentials_jwt = encoded_creds_jwt["jwt"]
    user_id = encoded_creds_jwt["user_id"]
    client_id = encoded_creds_jwt["client_id"]

    service_account_id = "123456789"
    service_account_email = client_id + "-" + str(user_id) + "@test.com"
    path = "/credentials/google/"
    data = {}

    # create a service account for client for user
    service_account = GoogleServiceAccount(
        google_unique_id=service_account_id,
        client_id=client_id,
        user_id=user_id,
        email=service_account_email,
        google_project_id="projectId-0",
    )
    db_session.add(service_account)
    db_session.commit()

    # make function return the service account we created and don't try to update db
    # since we already did it in the test
    mock = MagicMock()
    mock.return_value = service_account
    patch("fence.resources.google.utils.get_or_create_service_account",
          mock).start()
    patch("fence.resources.google.utils._update_service_account_db_entry",
          mock).start()

    response = client.post(
        path,
        data=data,
        headers={"Authorization": "Bearer " + encoded_credentials_jwt})

    # check that the service account id or email was included in a
    # call to cloud_manager
    args, kwargs = (cloud_manager.return_value.__enter__.return_value.
                    get_access_key).call_args
    combined = [arg for arg in args] + [value for key, value in kwargs.items()]
    assert service_account_id in combined or service_account_email in combined

    assert response.status_code == 200
Example #11
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.",
        )
Example #12
0
def test_google_create_access_token_post(app, oauth_client, cloud_manager,
                                         db_session):
    """
    Test ``POST /credentials/google`` gets a new access key.
    """
    client_id = oauth_client['client_id']
    service_account_id = '123456789'
    proxy_group_id = 'proxy_group_0'
    path = '/credentials/google/'
    data = {}
    with app.test_client() as app_client:

        # set global client context
        flask.g.client_id = client_id

        # get test user info
        user = (db_session.query(User).filter_by(username='******').first())
        user_id = user.id

        # create a  proxy group for user
        proxy_group = GoogleProxyGroup(
            id=proxy_group_id,
            user_id=user_id,
        )
        db_session.add(proxy_group)

        # create a service account for client for user
        service_account = GoogleServiceAccount(
            google_unique_id=service_account_id,
            client_id=client_id,
            user_id=user_id,
            email=(client_id + '-' + str(user_id) + '@test.com'))
        db_session.add(user)
        db_session.add(service_account)
        db_session.commit()

        response = app_client.post(path, data=data)

        # check that the service account id was included in a
        # call to cloud_manager
        (cloud_manager.return_value.__enter__.return_value.get_access_key
         ).assert_called_with(service_account_id)

        assert response.status_code == 200
def load_google_specific_user_data(db_session, test_user_d):
    """Add Google-specific user data to Fence db."""

    gpg = GoogleProxyGroup(id=userd_dict["gpg_id"],
                           email=userd_dict["gpg_email"])

    gsak = GoogleServiceAccountKey(
        id=userd_dict["gsak_id"],
        key_id=userd_dict["gsak_key_id"],
        service_account_id=userd_dict["gsa_id"],
    )
    gsa = GoogleServiceAccount(
        id=userd_dict["gsa_id"],
        google_unique_id="d_gui",
        user_id=userd_dict["user_id"],
        google_project_id="d_gpid",
        email=userd_dict["gsa_email"],
    )
    bkt = Bucket(id=userd_dict["bucket_id"])
    gbag = GoogleBucketAccessGroup(
        id=userd_dict["gbag_id"],
        bucket_id=userd_dict["bucket_id"],
        email=userd_dict["gbag_email"],
    )
    gpg_gbag = GoogleProxyGroupToGoogleBucketAccessGroup(
        id=userd_dict["gpg_to_gbag_id"],
        proxy_group_id=userd_dict["gpg_id"],
        access_group_id=userd_dict["gbag_id"],
    )
    uga = UserGoogleAccount(
        id=userd_dict["uga_id"],
        email=userd_dict["uga_email"],
        user_id=userd_dict["user_id"],
    )
    uga_pg = UserGoogleAccountToProxyGroup(
        user_google_account_id=userd_dict["uga_id"],
        proxy_group_id=userd_dict["gpg_id"])
    db_session.add_all([gpg, gsak, gsa, bkt, gbag, gpg_gbag, uga, uga_pg])

    user = (db_session.query(User).filter_by(
        username=userd_dict["user_username"]).first())
    user.google_proxy_group_id = userd_dict["gpg_id"]

    db_session.commit()
Example #14
0
def _create_google_service_account_for_client(g_cloud_manager):
    """
    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
    """
    # create service account, add to db
    proxy_group = (
        current_session
        .query(GoogleProxyGroup)
        .filter_by(user_id=flask.g.user.id)
        .first()
    )

    if proxy_group:
        client_id = getattr(flask.g, 'client_id', None)
        new_service_account = (
            g_cloud_manager.create_service_account_for_proxy_group(proxy_group.id,
                                                                   account_id=client_id)
        )

        service_account = GoogleServiceAccount(
            google_unique_id=new_service_account['uniqueId'],
            client_id=client_id,
            user_id=flask.g.user.id,
            email=new_service_account['email']
        )
        current_session.add(service_account)
        current_session.commit()
    else:
        # TODO Should we create a group here if one doesn't exist for some reason?
        # These groups *should* get created during dpbap sync
        flask.abort(404, 'Could not find Google proxy group for current user.')

    return service_account
Example #15
0
def test_google_create_access_token_post(
    app, client, oauth_client, cloud_manager, db_session, encoded_creds_jwt
):
    """
    Test ``POST /credentials/google`` gets a new access key.
    """
    encoded_credentials_jwt = encoded_creds_jwt["jwt"]
    user_id = encoded_creds_jwt["user_id"]
    client_id = encoded_creds_jwt["client_id"]

    service_account_id = "123456789"
    path = "/credentials/google/"
    data = {}

    # create a service account for client for user
    service_account = GoogleServiceAccount(
        google_unique_id=service_account_id,
        client_id=client_id,
        user_id=user_id,
        email=(client_id + "-" + str(user_id) + "@test.com"),
        google_project_id="projectId-0",
    )
    db_session.add(service_account)
    db_session.commit()

    response = client.post(
        path, data=data, headers={"Authorization": "Bearer " + encoded_credentials_jwt}
    )

    # check that the service account id was included in a
    # call to cloud_manager
    (
        cloud_manager.return_value.__enter__.return_value.get_access_key
    ).assert_called_with(service_account_id)

    assert response.status_code == 200
Example #16
0
def test_google_delete_owned_access_token(app, client, oauth_client,
                                          cloud_manager, db_session):
    """
    Test ``DELETE /credentials/google``.
    """
    client_id = oauth_client["client_id"]
    service_account_key = "some_key_321"
    service_account_id = "123456789"
    proxy_group_id = "proxy_group_0"
    path = ("/credentials/google/" + service_account_key)

    def get_account_keys(*args, **kwargs):
        # Return the keys only if the correct account is given
        if args[0] == service_account_id:
            # Return two keys, first one is NOT the one we're
            # requesting to delete
            return [{
                "name": "project/service_accounts/keys/over_9000"
            }, {
                "name":
                "project/service_accounts/keys/" + service_account_key
            }]
        else:
            return []

    (cloud_manager.return_value.__enter__.return_value.
     get_service_account_keys_info.side_effect) = get_account_keys

    with app.test_client() as app_client:

        # set global client context
        flask.g.client_id = client_id

        # get test user info
        user = (db_session.query(User).filter_by(username="******").first())
        user_id = user.id

        # create a  proxy group for user
        proxy_group = GoogleProxyGroup(
            id=proxy_group_id,
            user_id=user_id,
        )
        db_session.add(proxy_group)

        # create a service account for client for user
        service_account = GoogleServiceAccount(
            google_unique_id=service_account_id,
            client_id=client_id,
            user_id=user_id,
            email=(client_id + "-" + str(user_id) + "@test.com"))
        db_session.add(user)
        db_session.add(service_account)
        db_session.commit()

        response = app_client.delete(path, data={})

        # check that the service account id was included in a call to
        # cloud_manager
        assert any([
            str(mock_call) for mock_call in cloud_manager.mock_calls
            if service_account_id in str(mock_call)
        ])
        assert response.status_code == 204

        # check that we actually requested to delete the correct service key
        (cloud_manager.return_value.__enter__.return_value.
         delete_service_account_key).assert_called_with(
             service_account_id, service_account_key)
Example #17
0
def test_google_delete_all_owned_access_tokens(
    app,
    client,
    oauth_client,
    cloud_manager,
    db_session,
    encoded_creds_jwt,
    query_arg,
    valid_arg,
):
    """
    Test ``DELETE /credentials/google/*``.
    """
    encoded_credentials_jwt = encoded_creds_jwt["jwt"]
    user_id = encoded_creds_jwt["user_id"]
    client_id = encoded_creds_jwt["client_id"]

    service_account_key0 = "over_9000"
    service_account_key1 = "42"
    service_account_key2 = "one_MILLION_dollars"
    service_account_id = "123456789"
    service_account_email = client_id + "-" + str(user_id) + "@test.com"
    path = "/credentials/google/" + query_arg

    def get_account_keys(*args, **kwargs):
        # Return the keys only if the correct account is given
        if args[0] == service_account_id or args[0] == service_account_email:
            # Return multiple keys
            return [
                {
                    "name":
                    "project/service_accounts/keys/" + service_account_key0
                },
                {
                    "name":
                    "project/service_accounts/keys/" + service_account_key1
                },
                {
                    "name":
                    "project/service_accounts/keys/" + service_account_key2
                },
            ]
        else:
            return []

    (cloud_manager.return_value.__enter__.return_value.
     get_service_account_keys_info.side_effect) = get_account_keys

    # create a service account for client for user
    service_account = GoogleServiceAccount(
        google_unique_id=service_account_id,
        client_id=client_id,
        user_id=user_id,
        email=service_account_email,
        google_project_id="projectId-0",
    )
    db_session.add(service_account)
    db_session.commit()

    # make function return the service account we created and don't try to update db
    # since we already did it in the test
    mock = MagicMock()
    mock.return_value = service_account
    patch("fence.resources.google.utils.get_or_create_service_account",
          mock).start()
    patch("fence.resources.google.utils._update_service_account_db_entry",
          mock).start()

    response = client.delete(
        path,
        data={},
        headers={"Authorization": "Bearer " + encoded_credentials_jwt})

    if valid_arg:
        # check that the service account id was included in a call to
        # cloud_manager
        assert any([
            str(mock_call) for mock_call in cloud_manager.mock_calls
            if service_account_id in str(mock_call)
            or service_account_email in str(mock_call)
        ])
        assert response.status_code == 204

        valid_calls = [
            (service_account_id, service_account_key0),
            (service_account_id, service_account_key1),
            (service_account_id, service_account_key2),
            (service_account_email, service_account_key0),
            (service_account_email, service_account_key1),
            (service_account_email, service_account_key2),
        ]
        actual_calls = []
        # check that we actually requested to delete the correct service key
        for (call) in (cloud_manager.return_value.__enter__.return_value.
                       delete_service_account_key.call_args_list):
            args, kwargs = call
            actual_calls.append(args)

        assert set(actual_calls).issubset(valid_calls)
    else:
        # check that the service account id was NOT included in a call to
        # cloud_manager
        assert not any([
            str(mock_call)
            for mock_call in cloud_manager.mock_calls if service_account_id in
            str(mock_call) or service_account_email in str(mock_call)
        ])
        assert response.status_code != 204
Example #18
0
def test_google_delete_owned_access_token(app, client, oauth_client,
                                          cloud_manager, db_session,
                                          encoded_creds_jwt):
    """
    Test ``DELETE /credentials/google``.
    """
    encoded_credentials_jwt = encoded_creds_jwt["jwt"]
    user_id = encoded_creds_jwt["user_id"]
    client_id = encoded_creds_jwt["client_id"]

    service_account_key = "some_key_321"
    service_account_id = "123456789"
    service_account_email = client_id + "-" + str(user_id) + "@test.com"
    path = "/credentials/google/" + service_account_key

    def get_account_keys(*args, **kwargs):
        # Return the keys only if the correct account is given
        if args[0] == service_account_id or args[0] == service_account_email:
            # Return two keys, first one is NOT the one we're
            # requesting to delete
            return [
                {
                    "name": "project/service_accounts/keys/over_9000"
                },
                {
                    "name":
                    "project/service_accounts/keys/" + service_account_key
                },
            ]
        else:
            return []

    (cloud_manager.return_value.__enter__.return_value.
     get_service_account_keys_info.side_effect) = get_account_keys

    # create a service account for client for user
    service_account = GoogleServiceAccount(
        google_unique_id=service_account_id,
        client_id=client_id,
        user_id=user_id,
        email=service_account_email,
        google_project_id="projectId-0",
    )
    db_session.add(service_account)
    db_session.commit()

    # make function return the service account we created and don't try to update db
    # since we already did it in the test
    mock = MagicMock()
    mock.return_value = service_account
    patch("fence.resources.google.utils.get_or_create_service_account",
          mock).start()
    patch("fence.resources.google.utils._update_service_account_db_entry",
          mock).start()

    response = client.delete(
        path,
        data={},
        headers={"Authorization": "Bearer " + encoded_credentials_jwt})

    # check that the service account id was included in a call to
    # cloud_manager
    assert any([
        str(mock_call) for mock_call in cloud_manager.mock_calls
        if service_account_id in str(mock_call)
        or service_account_email in str(mock_call)
    ])
    assert response.status_code == 204

    # check that we actually requested to delete the correct service key
    args, kwargs = (cloud_manager.return_value.__enter__.return_value.
                    delete_service_account_key).call_args
    all_args = [arg for arg in args] + [value for key, value in kwargs.items()]
    assert service_account_id in all_args or service_account_email in all_args
    assert service_account_key in all_args
Example #19
0
def test_google_bucket_access_existing_proxy_group(
    app,
    google_storage_client_mocker,
    client,
    cloud_manager,
    db_session,
    encoded_creds_jwt,
    monkeypatch,
):
    monkeypatch.setitem(config, "MOCK_AUTH", False)

    user_id = encoded_creds_jwt["user_id"]
    client_id = encoded_creds_jwt["client_id"]

    service_account_id = "123456789"
    path = "/credentials/google/"

    proj = Project(id=129, name="test_proj")
    ap = AccessPrivilege(user_id=user_id,
                         project_id=proj.id,
                         privilege=["write-storage"])
    cloud = CloudProvider(id=129, name="google")
    bucket = Bucket(id=129, provider_id=cloud.id)
    gbag = GoogleBucketAccessGroup(id=129,
                                   bucket_id=bucket.id,
                                   email="*****@*****.**",
                                   privileges=["write"])
    ptob = ProjectToBucket(id=129, project_id=proj.id, bucket_id=bucket.id)
    sa = StorageAccess(project_id=proj.id, provider_id=cloud.id)
    service_account = GoogleServiceAccount(
        google_unique_id=service_account_id,
        client_id=client_id,
        user_id=user_id,
        email=(client_id + "-" + str(user_id) + "@test.com"),
        google_project_id="projectId-0",
    )

    db_session.add(service_account)
    db_session.commit()
    db_session.add(proj)
    db_session.add(ap)
    db_session.add(cloud)
    db_session.add(bucket)
    db_session.add(gbag)
    db_session.add(ptob)
    db_session.add(sa)
    db_session.add(service_account)
    db_session.commit()

    # make function return the service account we created and don't try to update db
    # since we already did it in the test
    mock = MagicMock()
    mock.return_value = service_account
    patch("fence.resources.google.utils.get_or_create_service_account",
          mock).start()
    patch("fence.resources.google.utils._update_service_account_db_entry",
          mock).start()

    encoded_credentials_jwt = encoded_creds_jwt["jwt"]

    path = "/credentials/google/"
    data = {}

    response = client.post(
        path,
        data=data,
        headers={"Authorization": "Bearer " + encoded_credentials_jwt})

    assert google_storage_client_mocker.add_bucket_acl.called is False
    assert response.status_code == 200
Example #20
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