4
votes

Using the Mobile Backend Starter (MBS) Android classes (those distributed as a sample project when creating a new project in Google Dev Console and demoed at Google I/O 2013) I'm able to insert new entities to the cloud datastore via calls to CloudBackendMessaging.insertAll or .updateAll. The latter will create entities if none exist so seems functionally identical to insert for new records.

The insertion/creation works fine. However when I attempt to update existing entries in the datastore, I received permissions errors e.g. (from the backend log)

Method: mobilebackend.endpointV1.updateAll

Error Code: 401

Reason: required

Message: Insuffient permission for updating a CloudEntity: XXXXXX by: USER: YYYYYYY

which results in a matching access error in the logcat client side.

In all cases I am using Secured access authenticating with a valid Google account (my own).

The entities being inserted are thus showing as "owned" by my user ID with "updated by" and "created by" showing my Google account's email address.

However when the update of the existing record is made, using exactly the same CloudBackendMessenger object and thus same credentials etc. the backend is telling me I can't update due to permissions issues. But surely if I just made the entity with the same credentials this can't be correct? Looking at the documentation it appears that I should be able to edit entities owned by the same user ID in all cases (regardless of the KindName and whether it is prepended [public], [private] or nothing).

Can anyone who has received permissions errors on UPDATES via Mobile Backend Starter for Datascore please shed any light? I have been banging my head over this for most of today.

3
It seems a workaround on this is to query i.e. get the CloudEntity you want to update e.g. via a list() call, and then update it via an update() call. However it would be nice / more efficient if you could directly execute an update on an Entity (specified via it's UID i.e. setId()) without having to get it first.jcollomosse
Did you also try using "transactions" to update a single entity?developers.google.com/appengine/docs/java/datastore/…Franz Noel
@Franz Noel. That's interesting - could you please elaborate on how transactions can be used with MBS on the mobile/client side with a CloudEntity in this way perhaps with a code snippet?jcollomosse

3 Answers

0
votes

I've faced the similar error "Insuffient permission for updating a CloudEntity" when using cloudBackendAsync.update(cloudEntity). I resolved it by making sure the cloudEntity has it's createdAt field set. createdAt is autogenerated and I think I am not supposed to touch it. But it worked for me. In my case I am first obtaining list of cloud entities. This is when I get createdAt field of cloud entities. Then when I am updating I setting the createdAt field from previously obtained entities. Edit: Had to do similar thing for owner field also.

0
votes

Similar to one of the comments above, I successfully got around this by getting the original CloudEntity before doing the insert/update/delete function.

    CloudQuery cq = new CloudQuery("datastoretype");
    cq.setLimit(1);
    cq.setFilter(Filter.eq("_id",id));

    cloudEntity.setId(id);
    mProcessingFragment.getCloudBackend().get(cloudEntity, handler);

Thereafter it was trivial to do the following:

    mProcessingFragment.getCloudBackend().update(cloudEntity, handler);

The docs definitely ought to be more clear on this, whether it is a strict requirement or bug.

0
votes

The answers posted so far work around the problem if you don't mind all users being able to access the entity you are trying to update. However, a better solution that retains the access permissions is detailed by google here - https://cloud.google.com/cloud/samples/mbs/authentication

If you want to pass the user’s Google Account info to the backend on each call, use the CloudBackend#setCredential() method (also available on the subclasses, CloudBackendAsync and CloudBackendMessaging) to set a GoogleAccountCredential object before calling any Mobile Backend methods.

GoogleAccountCredential credential = GoogleAccountCredential.usingAudience(this, "<Web Client ID>");
credential.setSelectedAccountName("<Google Account Name>");
cloudBackend.setCredential(credential);

Setting credientials enables the client to operate when the backend is in “Secured by Client ID” mode and also sets createdBy/updatedBy/owner properties of CloudEntity automatically.