Owner Policy seems to bypass API Key Policy

Hi Backendless Team,

Application ID: censored

I’m having an issue with owner policy whereby the owner can update their user object even though the api key they are sending the update with has a deny X on the Update function:

API Key:
image

UserRole with UPDATE set as DENY X

Object in question testing with:

Testing an update of their object using the API Key (the user is logged in and I’m passing the user token in the header)

The object is updated and admin is now set to true.

It was my understanding that if the API they are using explicitly denies UPDATES that it would stop all updates on that table regardless of the owner policy.

The owner policy does have update to true:


But as I mentioned above the API key is deny so it should block this?

I only want to be able to update that admin flag via the cloud code, it works fine if I set the user as not owning that object.

Hello @Reece_Smith

I am could not reproduce your issue in the Rest console, and Posman too. In my case, all works as I want. Also, I try to reproduce in your app. and catch this response:

image

Could you please tell me what you do step by step with details?

Hi Vak,

As discussed, I have shown you on the chat and you can now replicate.
As it stands any user that registers for a backendless app is automatically created as the ownerid for that object.
That user assuming they have an owner policy of update can bypass the Custom Key role permissions and update their object.
Following this guide this shouldn’t be possible: Security - Backendless SDK for JavaScript API Documentation
Layer two is before the Owner policy.

The user defined role on my app which is linked to the custom key is completely bypassed (it has update as crossed) and the user can still update their object.

Hi @Reece_Smith,

We investigated this issue further. The reason you’re seeing this behavior is that the roles associated with API keys (such as the TippleUserRole) are handled as system-defined roles and thus are placed at level 7, which is below Owner Policy. The actual problem is that the documentation does not reflect that and I am scheduling an internal ticket to fix that.

In order to achieve the behavior you’re after, you should create a user-defined role, assign it to the user (either in console or via API) and customize the permissions for that role.

Kind regards,
Mark

Hi Mark,

I just assigned user role ‘TEST’ to the user we are testing with:

Set the role to have zero access:

Tried updating the object via a PUT in postman:
http://api.backendless.com/08B538C0-0E98-1827-FF98-7DF8AFF96600/Tipple KEY/users/710F9D9A-1FF0-4536-A980-A21CC4F6BBF8
Body:
{
“admin” : true
}

And it updated fine. So the custom user roll still isn’t blocking the owner policy?

What is the name of the table where you update an object?

The one I’m testing with is the User table

Thanks. There are two more questions:

  1. Does the user update himself or some other user?
  2. The user that is being updated, who is the owner of that user? The one that performs the update?
  1. Updates himself
  2. Yes.


    The PUT request above is using the user-token from a standard login for that user:

Here’s what I did:

  1. I changed the table permission to explicitly deny the UPDATE operation for the TEST role.
  2. I created a test user with my email address and assigned the TEST role to me
  3. I logged in as myself in the Backendless REST Console
  4. I tried updating myself and got the expected error:

Thanks Mark, that now stops the user from being to update directly via the REST console/postman.

The problem I have now is that the user calls a custom api command in business logic, this command does some logic to check that the user can be admin, then tries to set the user property admin to true, it now comes back saying 400 - User has no permission to update entity (1012)
The Server code user has full perms:


I assume this is because its being blocked on the user role calling the custom api endpoint.

How do you suggest handling this? Is there anyway on the cloud code that I can say forget the user that is making the call to this function?

Make sure the Admin role has explicit grant permissions for the table where you make the changes. If it is still the Users table, I see that the Admin role has no explicit permissions there. Keep validating against the list below on this page. It is by far the most important piece of information when it comes to security tiers in Backendless:

How does the Admin role fit in here? Are you suggesting login as a user with Admin role set on cloud code to execute the update on the user that’s called the API command? I’ve explicitly set the role to have grant on the table.

The list from the page you references states 4.Table Permissions for the user-defined roles - this we have just set to have deny on update.
The only way I can think is that we somehow tag the user with the admin role when we want to do the update…
InvocationContext.setUserRoles("Admin");
This isn’t probably the right way to do it/it doesn’t work.

I assumed you’re checking if the user has the Admin role when you wrote this:

To assign a role to a user, you can use the following API:
https://backendless.com/docs/js/users_user_roles.html#assigning-a-role-to-a-user

Just to be clear this is the problem:

  1. I want to stop users being able to update their objects directly if they get hold off the app id and key the app is using to communicate with backendless. - This has been done now that we have added a custom role ‘TEST’ that blocks this.

  2. I want the user to be able to call the Business Logic Cloud Code API Endpoint ‘updateUserSetAdmin’ which will process some logic to and make sure the user calling can be an admin, if the logic succeeds then it simply updates the users admin flag to true. Business Cloud code logic for updating object:

    BackendlessUser activeUser = Backendless.UserService.findById(InvocationContext.getUserId());
    Map<String, Object> usrToUpdateProps = activeUser.getProperties();
    usrToUpdateProps.replace(“admin”, true);
    activeUser.setProperties(usrToUpdateProps);
    Backendless.UserService.update(activeUser);

The problem we have now is that the user is assigned to role ‘TEST’ and we get an error back saying doesn’t have permission to update object, when the above business logic cloud code executes.

Are you suggesting that in the logic we add the user to the ‘Admin’ role, make the change, then remove the user from the ‘Admin’ role.

There must be an easier way of doing this? I’d expect the backend cloud code to be able to do what it wants regardless of the user calling the endpoint. I think I asked earlier, is there a way to just forget that a user is calling the endpoint so we can do all the processing.

One way to do this is to disassociate the currently logged in user from the invocation context. Try to do the following before you use the update API call:

HeadersManager.getInstance().removeHeader( HeadersManager.HeadersEnum.USER_TOKEN_KEY );

Mark my friend, you are a genius, this solves all the issues. Here’s me worrying I would need to find a new backend provider.
Definitely worth documenting this somewhere as I can imagine there are a large amount of insecure backendless apps around.

Thanks again.