How to make a table only accessible by the business logic

Hello,

my scenario is that two users can find each other through a MatchingService (hosted business logic) and then create a match/bond as a new entry in a new table. I want to make sure that these entries can only be created by the MatchingService and that only the matched users can see/find that specific entry. The business logic also has to be able to remove and update the match entry, but not one of the users directly. They always have to call through special service methods to do that.

My current approach (which does not work):
I set the owner policy to deny everything, but never actually set to owner so that should not change anything.
I set that as the permission matrix for the matches table:
http://support.backendless.com/public/attachments/6f7e7488faca5193f5031c517138e51c.PNG</img>
And when the Match is created in the server code I invoke

DataPermission.FIND.grantForUser(first_user.getUserId(), match);
DataPermission.FIND.grantForUser(second_user.getUserId(), match);
But I cant’t even create the match in the server code so that part is never executed.

How can I achieve this? I have read quite some other posts here but no one has solved my problem.

Thanks in advance
Felix D.

Hi Felix,

You’re almost there… What’s missing is the permissions for either NotAuthenticatedUser or AuthenticatedUser. It is the combination of ServerCodeUser and one of the above that will give the ultimate permission to the table.

The reason I mentioned either NotAuthenticatedUser or AuthenticatedUser is you should choose whether business logic will be authenticating itself (logging in) as some special “admin” user, in that case the AuthenticatedUser should be granted access or will make calls without logging in (the NotAuthenticatedUser approach).

Since the roles for all other API keys are rejected access, it will ensure that only business logic can work with the table.

Regards,
Mark

Uhm, it somehow does not work. For simplicity, I chose to use the NotAuthenticatedUser approach:

That is my owner policy:
http://support.backendless.com/public/attachments/f32bb6e58799da6644ac9006cbd996e1.PNG</img>

And this is my permission matrix:
http://support.backendless.com/public/attachments/7332879794c60f0706f4a929536b7638.PNG</img>

The user (with the roles: AuthenicatedUser, AndroidUser, FacebookUser and I guess SocialUser) accesses a service method getCreateMatch(id_of_the_other_one) in MathchingService. There I use something like the following to create the match:

Match match = new Match();

match.someField = "my value";
Backendless.Persistence.of(Match.class).save(match);
DataPermission.FIND.grantForUser(match.initiator.getUserId(), match);
DataPermission.FIND.grantForUser(match.receiver.getUserId(), match);

The client app invokes the Service with that method:

Backendless.CustomService.invoke(String serviceName, String serviceVersion, String method, Object[] arguments, Class<?> clazz, AsyncCallback<E> callback);

But that fails with the following message:

BackendlessFault{ code: '1011', message: 'User has no permission to create entity' }

What am I doing wrong here? The code worked perfectly fine before I restricted the permissions for obvious security reasons.

Sorry, I am confused now. I thought you said you wanted to give access to the table exclusively the business logic (server-code)? Now you say “The user (with the roles: AuthenicatedUser, AndroidUser, FacebookUser and I guess SocialUser)”, that’s not a server-code user, is it? Of course, there are no permissions for that user - look at the permissions for the listed role - they are denied access for the table.

Well, the user invokes the remote service method in the hosted service. I have a server-side class like this:

@Asset("*")
public class MatchingService implements IBackendlessService { ... }

with the getCreateMatch(…) method in it. There (in the server code) the match is created, saved and the permissions are set. At least in theory that should happen.

The service is uploaded like that:

http://support.backendless.com/public/attachments/421b1e5988348b84b07fe858bc1fb656.PNG</img>

And the user invokes it asynchronously using that SDK method (I am developing for Android):

Backendless.CustomService.invoke(String serviceName, String serviceVersion, String method, Object[] arguments, Class<?> clazz, AsyncCallback<E> callback);

So the client app invokes the business logic code which then saves a Match object and assigns FIND permissions to it for initiator and receiver.

Which part is not working? The invocation within the business logic code?

Btw, do not restrict access in the Owner Policy, it makes the security matrix unnecessarily complex.

Regards,
Mark

Okay, I have set everything in the owner matrix to “inherit”, which is “allow” in this case.

The problem is in the server-code, right. It is that line that causes the permission error:

Backendless.Persistence.of(Match.class).save(match);

I somehow cannot save the new Match.

What is your app ID?, I’d like to give it a try.

My App’s ID is: 38A72038-B79A-5883-FFCB-08F843D77C00. Thank your for your support!

Hi Felix,

I looked into your app. Adding objects to the Match table is not a problem, it works - as you can see I created an object in there from my code. I suspect the problem is elsewhere. Does your MatchingService try creating an object in the Users table perhaps? I see you’re passing properties of the initiator and receiver into the service, which led to me believe the service would be creating Users before the Match is saved.

Regards,
Mark

No I do not think so. I reduced my code to the following, without solving/changing the issue:


public Match getCreateMatch(String receiver_id) {


    String initiator_id = InvocationContext.getUserId();
    BackendlessUser initiator = Backendless.UserService.findById(initiator_id);


    Match match = new Match();
    // for this test i do not set the initiator or receiver fields
    match.confirmed = false;


    Backendless.Persistence.of(Match.class).save(match);
   
    // this is never reached, instead a error is returned to the client:
    // BackendlessFault{ code: '1011', message: 'User has no permission to create entity' }
    throw new IllegalStateException("custom error");


    // more code
}

The code on line 4 above fails in my test with the following exception:

BackendlessException{ code: '1013', message: 'User has no permission to find elements in persistence storage.' }

The failure occurs because of the following:
http://support.backendless.com/public/attachments/2a44d7e3f9fd253b3dd5fd9f5224d142.png</img>

The reason my original example worked is because I created a test user object which I used to login in the server-code and perform lookups of initiator and receiver.

Regards,
Mark

Okay I think I solved the problem for now. Thank you very much!