2
votes

I am using mobile backend starter and I am trying to update an entity when using the secured by id setting. I keep getting the error

com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 Unauthorized
    {
    "code": 401,
    "errors": [
    {
    "domain": "global",
    "location": "Authorization",
    "locationType": "header",
    "message": "Insuffient permission for updating a CloudEntity: CE:123456 by: USER:123456",
    "reason": "required"
    }
    ],
    "message": "Insuffient permission for updating a CloudEntity: CE: 123456 by: USER:123456"
    }

The documentation (https://cloud.google.com/developers/articles/mobile-backend-starter-api-reference/#ciagaa) states

In the code below, the backend allows the call in “Secured by Client ID” mode. It also sets createdBy/updatedBy/owner properties of CloudEntity automatically

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

So I wrote the following code

mCloudBackend = new CloudBackendMessaging(this);

GoogleAccountCredential credential = GoogleAccountCredential.usingAudience(this, Consts.AUTH_AUDIENCE);
    mCloudBackend.setCredential(credential);
    String accountName =
            mCloudBackend.getSharedPreferences().getString(
                    Consts.PREF_KEY_ACCOUNT_NAME, null);
    credential.setSelectedAccountName(accountName);
    mCloudBackend.setCredential(credential);
    newPost.setId(updateRide);
    mCloudBackend.update(newPost, handler);

Unfortunately this is giving the error above. However, the update is going through as I can see changes in entity when I query the datastore. The problem seems to come from the fact that the createdBy/updatedBy/owner properties are set to null and so are not being set automatically.

I have seen other questions where the answer has been to query the entity prior to the update, use this to set the aforementioned properties and then perform the update. I would rather avoid this as it seems like an unnecessary call to the datastore. So my question is how to I get the GoogleAccount createdBy updatedBy and owner properties?

1

1 Answers

1
votes

I faced similar problem while playing with the mobile backend starter source.And even though I followed the answers provided in this link,I wasn't able to resolve the issue.However,what I did was to grab the mobile backend source code and make some modifications.Grab the code and in the CrudOperations.java file,you will see this method

private Map<String, Entity> findAndUpdateExistingEntities(EntityListDto cdl, User user)
 throws UnauthorizedException{

// create a list of CEs with existing Id
EntityListDto entitiesWithIds = new EntityListDto();
Map<String, EntityDto> entitiesWithIdMap = new HashMap<String, EntityDto>();
for (EntityDto cd : cdl.getEntries()) {
  if (cd.getId() != null) {
    entitiesWithIds.add(cd);
    entitiesWithIdMap.put(cd.getId(), cd);
  }
}

// try to get existing CEs
Map<String, Entity> existingEntities = getAllEntitiesByKeyList(entitiesWithIds
    .readKeyList(user));

// update existing entities
for (String id : existingEntities.keySet()) {

  // check ACL
  Entity e = existingEntities.get(id);
  SecurityChecker.getInstance().checkAclForWrite(e, user);

  // update metadata
  EntityDto cd1 = entitiesWithIdMap.get(id);
  cd1.setUpdatedAt(new Date());
  if (user != null) {
    cd1.setUpdatedBy(user.getEmail());
  }

  // update the entity
  cd1.copyPropValuesToEntity(e);
}
return existingEntities;

}

From the above code,comment out SecurityChecker.getInstance().checkAclForWrite(e, user); and the throws UnAuthorizedException lines and redeploy your backend.Doing so will make all users of your app able to make updates to the concerned entity.This could be risky if you are strictly concerned about ownership.So,consider your security concerns before taking this approach.Haven done that,you can now freely update the concerned cloud entity.Remember to make as default your newly deployed backend on the server side.