Our Data Service supports a very flexible security mechanism for restricting access to objects stored in Backendless. Security permissions apply to users and roles. A permission can either grant or reject an operation for a particular asset. In the context of Data Service, the asset is an object which your app can retrieve, update or delete. Permissions can be granted or rejected globally, where they apply to all tables and all objects in the data store. Additionally, every table may have its own permission matrix and owner policy – a special instruction whether object owners can or cannot retrieve/update/delete the objects they ‘own’. Finally, every object has its own Access Control List (ACL) which is a matrix of permissions for the operations applicable specifically to the object:
The security system is multi-layered. For an API call to retrieve, update or delete object(s), the system goes through several where each can trim the scope of the operations. The layered order of decision-making is important and consists of the following:
- ObjectACL for the user who makes the call
- ObjectACL for user-defined roles assigned to the user who makes the call.
- Table permissions for the User account
- Table permissions for the user-defined roles
- Owner Policy
- ObjectACL for system roles
- Table permissions for system-level roles
- Global user-defined roles
- Global system roles
Where:
- “User-defined roles” – roles created by the application developer
- “System roles” – roles built into Backendless (Authenticated User, NonAuthenticated User, SocialUser, etc)
Consider the following guide which illustrates the decision-making process:
- Backend receives an API request to load data from a table (the Find operation). All objects become candidates for the retrieval. Backendless goes through the security permissions chain to determine which ones must be included.
- ObjectACL for the user who makes the call. Backendless checks if there are any restrictions for the user account at the object level. Any object in the collection with ACL which rejects access to the user is excluded from the result. To see or modify the permissions for a particular object, click the ‘key’ icon in the ACL column in the data browser in management console.
- ObjectACL for user-defined roles assigned to the user who makes the call. This is the same check as the one above, except Backendless looks into the permissions for the roles defined by the application developer. If the user belongs to any of the custom roles, Backendless checks if these roles are allowed to perform the current operation. In the screenshot below, only the “MyRole” role will be checked in this step, since this is the only custom role in the application:
- Table permissions for the User account. Every table in Backendless may have its own set of permissions for users and roles. At this point Backendless checks if the currently logged in user is allowed to run the current operation. For example, if the Find operation is denied for the user, no objects would be returned.
- Table permissions for the user-defined roles. This step is identical to the one described above with the exception that is checks custom roles for the table. Since this guide reviews the decision making process for the Find operation, Backendless checks the column for Find. If any of the custom roles deny access, the operation is rejected and no data is returned.
- Owner Policy. When a new object is created in Backendless, the system automatically links it with the account of the currently logged in user. You can see that information in the ‘ownerId’ column in any of your tables in the data browser. With the association between objects and users, Backendless provides a way to control whether users can get access to the data they created. This is done through a concept we call ‘Owner Policy’. The policy is available on the ‘Schema and Permissions’ screen. Select a table in the data browser and click the ‘Table Schema and Permissions’ button in the upper right corner. Select the ‘Owner Policy’ menu item. Owner policy can be global (select ‘All Tables’ from the drop down in the upper right corner) or it could apply to a specific table.
Granting a permission for an operation in Owner Policy, guarantees that the objects owned by the current user will be included in the resulting collection. Denying a permission, takes out the ‘owned’ objects from the collection of candidate objects to return. Consider the following:
Granting Find permission in Owner Policy:
Results in the following. The objects with bold border are guaranteed to be returned. All other objects will be subject to the subsequent permission checks.
However, if the Owner Policy rejects a permission:
The objects owned by the current user will be excluded from the resulting collection. All remaining objects will be decided by the subsequent permission checks.
- Object ACL for system roles. This check is identical to step 3 (Object ACL for custom roles). The difference is the system roles cover larger groups of users. For example, this step would make possible to restrict access to specific objects for all authenticated (or not authenticated) users, yet the object would be returned with a query made by the object’s owner if the Owner Policy (previous step) grants access.
- Table permissions for system roles. Identical to step 5, this checks if any of the system roles reject the operation at the table level.
- Global custom roles. Global policy applies to all tables and objects. By default all table level permissions inherit from the global policy. You can configure in the console at: Users > Security and Permissions. Create a new role and click it to configure the permission matrix:
- Global system roles. This is the same as the step above, but checks the built-in system roles (AuthenticatedUser, NonAuthenticatedUser, SocialUser, FacebookUser, TwitterUser).
As you can see the system is very rich and could get very complex. We plan to post a few scenarios showing how to configure the system. If you can think of any scenarios, post them in the comments and we will be happy to show how to handle it with Backendless.