setting ACL on object fails in customBusinessLogic

I want to create some ACL’s when an object is created or updated. The idea is that a ‘Super Admin’ can create the objects, associated with some users, and that the objects created will get ACL’s set on them so that the associated users can find and update them too.

So I have a role called ‘SuperAdmin’ which is has full permission set on the object (called Administrator) and I denied permissions for all other roles.

When the backend code runs I get an error saying that the user cannot update permissions as it is not privileged to do so. I assumes that the backend code runs in the context of the RestAPI user (which is a member of the ‘SuperAdmin’ role) making the request so not sure why this does not work (the object is getting created with the correct OwnerId and when I print the user in the context object in the backendLogic it is also the user that is the member of the superAdmins group).

To make it work, I seem to have to allow ‘Unauthenticated User’ role to set permissions (at least in the inherited mode). This seems wrong seeing as I do not want unauthenticated users to be able to do anything with these objects, so I ought to be able to deny access here.

By default the backend code does not impersonate any users, it runs all the invocations as a NonAuthenticatedUser. However, any invocations coming from server-code will have the ServerCodeUser role assigned to them (based on the secret key used). Your options are:

    Grant any special privileges to the ServerCodeUser role or

    Create a special user which would have the permissions to do whatever is needed and login as that user fro your server-side code.

Regards, Mark

In parse the operations ran as the user making the update (i.e. as part of their transaction). Now I will have to hardcode a password for a ‘special’ account. if someone changes that they it will all go wrong. Feels a little fragile to me. Parse also had a special ‘run as super person’ mode that enabled the business logic to do anything too, that might be a better option. I guess I could put a check in my business logic to see what user role is making the call first too (I assume that info is in the context of the call).

For now I guess I will hardcode a known password. If that account is ever breached, then I will have to update all the business logic too. If you used the ‘super person’ mode in parse, then the keys could change without any need for code changes to continue operation.

The only “someone” who can change the password would be developer with access to Backendless console.

What’s wrong with the first approach I described?

Sure I guess I could give the server code role the permissions I will try that first.

Ok, so that does not work as expected… I could do with some advice…
Here are the permissions setting ServerCodeUser to have all permissions

http://support.backendless.com/public/attachments/70a4b63b42499a3bd6a7a1e5de34fa55.png</img>

and here is the error in the debugger…
http://support.backendless.com/public/attachments/66955e22ee50860faeda694f074b604c.png</img>

Showing the ‘user has no permissions’. How come the code below does not work… it should run as serverCodeUser and therefore be able to update the permissions.

// this will require the serverCode user to be able to set permissions on the administraor objects
// as the code here does not run in the callers context.
@Override
public void afterCreate( RunnerContext context, Administrator administrator, ExecutionResult<Administrator> result ) throws Exception
{
    System.out.println( "operating as userID " + context.getUserId());
    System.out.println( "About to insert  object into the data store" );
    System.out.println( "Company name -" + administrator.getCompanyName() );
    updateAcl (administrator, administrator.getUsers());
    System.out.println( "Finished insert  object into the data store" );
}

// make the ACL list match the user list for the admin
private void updateAcl(Administrator administrator, List< BackendlessUser> users) {
    if (users != null) {
        Iterator<BackendlessUser> userItr = users.iterator();
        while (userItr.hasNext()) {
            BackendlessUser user = userItr.next();
            DataPermission.FIND.grantForUser(user.getObjectId(), administrator);
            DataPermission.UPDATE.grantForUser(user.getUserId(), administrator);
        }

    }
}

Also I can’t find anything that explains what I can do in one of these event Handlers to reject the action… i.e. what do I do to validate and reject the insert so that the object does not get created.

I assume “administrator.getUsers()” does not make a remote call.

other than that everything looks good. Out of interest and as a test, if you grant the NonAuthenticatedUser the Permission permission, does it work?

administrator.getUsers() just returns the backendUser objects associated in a related to many property of the administrator table.

Granting the NonAuthenticatedUser the Permission does fix it yes. but that clearly would allow anyone to make the update :slight_smile: Looks like there is a bug here to me that the back endless code is not running in the ServerCodeUser Role. Can you confirm that, its a bit of a show stopper right now.

but that clearly would allow anyone to make the update :) 

Only if they have access to the server-side secret key…

ok… just to confirm… are you saying that NonAuthenticatedUsers cannot be from client side, only from server side. If so then that is probably ok, as it means that only the business logic can make the change. If thats the case whats the difference between this and the serverCodeUser role??

The docs say
NotAuthenticatedUser - automatically assigned to any user who has not authenticated to a Backendless application.

Which implies that anyone with a rest key could do it… which is not secure at all seeing as it could be in scripts all over the place.

You are missing the main point. You denied access to the RestUser role. Which means anyone accessing the system with REST key would be denied. Same for android, ios, etc…

Thank you for pointing that out :slight_smile: ACL’s can get very confusing at times. I appreciate the help…

Just one more thing then…

how do you remove dadapermissions from an object, so if a user has specifically been added to the ACL for an objects Find using

DataPermission.FIND.grantForUser(user.getObjectId(), administrator);

How do you remove it (not set it to deny, but remove it from the list so its like it was before it was added). I want to reset the ACL to a new set of users and want to remove all existing ACLs, and I can’t for the life of me see what to do here.

This can be done in console (or with the Management API used by console, which is not free, a function pack is required). We will need to add something like DataPermission.FIND.resetForUser( objId, user )

Ok, but the method cannot include the user as I would not know what user needs removing, so really need DataPermission.FIND.resetAll(object). This is needed to clear out permissions before re-adding new ones. Alternatively have the set permission take a List<object> and make this a complete operation rather than additive, so I could just set the list in one call and it becomes the complete set.

So is this something that you are going to do. paying $5/month for the management pack is a high cost for just wanting to clear an ACL.

By the way I also notice that you cannot update ACL as part of a before create method either it blows up with an objectId cannot be null error too. Is this an error.

I need to discuss it with the team first before I commit publicly.

Modifying object’s ACL in the before create handler will not work as the object does not exist in the persistent storage at that time.