. . .

Data access security


Limiting access to data is one of the most crucial points of developing an app. With ApiOmat, you can define the various levels of access to either classes and/or objects to make your application as secure as you want.

Basic access rules

With every app you create, you can define roles needed to interact with your data. This is done in the class editor using the security panel.

images/download/attachments/78782488/auth_overview.png

Predefined roles are:

  • Everybody – Everybody having your API-Key (can be found in the App-Setup page on the dashboard); username/password credentials are not needed.

  • App user – The users of your app; all instances of the class User or derived classes have a username and a password.

  • Object owner – The user who created the specific object.

Roles have a hierarchical behavior. If a guest is able to write an object of the class, a user or the owner can as well.

You can also define a role for each type of interaction with objects:

  • Create – Object is initially created (POST)

  • Read – Object is read (GET)

  • Write – Object gets updated or deleted (PUT/DELETE)

Using the radio buttons in the security panel, you can set separate roles for each method. Since the combination of owner and create does not make sense, the radio button is missing here.

All these settings are on a class level basis, meaning that all objects of the selected class follow the settings you chose for that class.

While these possibilities may suffice for most use cases, ApiOmat allows you to configure access in two much more detailed ways:

  • using ACLs

  • using Dynamic Roles / custom role check methods

Note regarding the default User class

The default access rules of the basics.User class allow all users to read the data of other users. You can either create a subclass and modify the access rules, or change the configuration of the module "Basics" accordingly (see Basics Module).

Access Control Lists (ACL)

ALCs enables you to do two major things:

  1. define your own roles

  2. Use these roles to set permissions on class and object levels

With ACLs, you can set grant rights in addition to create/read/write. The grant right is needed to modify the ACLs for an object. With no grant roles defined, only the owner of an object has the right to modify object ACLs. If grant roles are specified, even the owner needs to be in that role. Grant is also hierarchical, meaning that users with grant right can also write or read.

Resources

If you do not want your resources (files or images) to be accessed by guests, you can check the “Restrict resource access” box in the security panel. Each resource you attach to an object after setting this option will recive the read and write permissions of the object automatically (the permission that's defined in the class of the object as well as the object-specific permission). For example, if your class is readable by role “myRole”, the resources attached to objects of that class are as well.

If you use the Dynamic Roles feature introduced in ApiOmat 3.0.0 and have a custom role check method assigned to a class, and use restrictResourceAccess, the role check method will also be called when a request to the resource is received (only since ApiOmat v3.0.1).

Please pay attention that the "restrictResourceAccess" setting only applies to new resources, not to those added to an object before the setting.


When adding a resource to multiple objects, only the permissions of the latest object are copied to the resource. This only applies when using the direct URL of a resource and making a PUT request to multiple objects. This is not the case when using the Dashboard > v3.0.0, SDK > v2.6.1 or new static data REST endpoints directly, because in those cases a new resource is created with every request.

Roles

In addition to the three roles Everybody, User, and Owner, you can create your own roles in data editor or via SDK's and use the role names in the security settings. Creating a role in the data editor is very easy:

  1. switch to data editor

  2. select the Role class in Basics module on the left menu

  3. hit the plus icon on the upper right to create a new role

  4. define a name for the role in the popup

  5. add user names of the users who have this role in the members attribute

images/download/attachments/78782488/addNewRole.png

Back in the class editor, you can select the Roles (ACL) radio button for the method you want to allow for your group (read/write/grant). Select the Roles name next to the radio button. You can add even more roles, each on a new line. Hit deploy and you are done.

One thing to remember:Using ACLs forbids access to the class or object to all users who are NOT members of the role. This includes owners of an object!

Object level permissions

Now that you have your own roles, you can do even more than just define class level permissions: You can also set role permissions on object level.
Therefore, each object has the three attributes

  • allowedRolesRead

  • allowedRolesWrite

  • allowedRolesGrant

Like in the class editor, you can add one role name per line here which is allowed to read the object, write the object or which role is allowed to change the ACLs for this object (the grant privilege). All settings from the class level are inherited; if you allow role A to write the object on class level and role B on you objects level, then all users in role A and B will be able to write the object. You can not remove the roles defined on class level on the object.
You can, however, set both roles and these object-based values in your SDK with the setter methods and with server code.

New attributes since ApiOmat 2.5

As of ApiOmat version 2.5, you have the possibility to distinguish the roles from class level and object level within the returned JSON response. For now, there are additional fields named allowedRolesReadFromClass, allowedRolesWriteFromClass, allowedRolesCreateFromClass and allowedRolesGrantFromClass which include the class level settings and the fields. The object level settings are contained in the fields allowedRolesReadFromObject, allowedRolesWriteFromObject and allowedRolesGrantFromObject.

The combined values are still available in allowedRolesRead, allowedRolesWrite and allowedRolesGrant.

You can get these fields in the JSON response and also in our Dashboard, but unfortunately, these fields are currently not available in our SDKs. We're currently working on this issue to make these fields available in the SDKs.


The following Java example (other languages are similar) will show how to create an “agent” role with two users which have access to
a secret document:

Android

Android
Role agents = new Role();
agents.setName("agents");
String[] agentNames = { "Foo", "Bar" };
agents.setMembers(Arrays.asList(agentNames));
agents.saveAsync(new AOMEmptyCallback() {
@Override
public void isDone(ApiomatRequestException exception) {
if (exception != null) {
// ...
}
}
});

Objective-C

Objective-C
AOMRole *agents = [[AOMRole alloc] init];
[agents setName:@"agents"];
NSMutableArray *agentNames = [NSMutableArray arrayWithObjects:@"Foo", @"Bar", nil];
[agents setMembers:agentNames];
[agents saveObjCWithLoadAfterwards:true completion:^(NSError * error) {
if(error)
{
...
}
}];

Swift

Swift
var agents = AOMRole()
agents.name = "agents"
let agentNames = ["Foo", @"Bar"]
agents.members = agentNames
agents.save { (error) in
if error {
...
}
}

JavaScript

JavaScript
var agents= new Apiomat.Role();
agents.setName("agents");
var agentNames=["Foo","Bar"];
agents.setMember(agentNames);
 
var saveCB = {
onOk : function() {
console.log("saved");
onError : function(error) {
console.log("Some error occured: (" + error.statusCode + ")" + error.message);
}
};
agents.save(saveCB);

TypeScript

TypeScript
const agents = new Role();
agents.name = "agents";
agents.member = ["Foo", "Bar"];
await agents.save();

Now you can create a document and allow access only to the users listed as the role “agents”:

Android

Android
Document doc = new Document();
doc.setName("Secure document! Burn after reading!");
String[] docReaders ={"agents"};
doc.setAllowedRolesWrite(new HashSet(Arrays.asList(docReaders)));
doc.saveAsync(new AOMEmptyCallback() {
@Override
public void isDone(ApiomatRequestException exception) {
if (exception != null) {
// ...
}
}
});

Objective-C

Objective-C
Document *doc = [[Document alloc] init];
[doc setName:@"Secure document! Burn after reading!"];
NSMutableArray *docReaders = [NSMutableArray arrayWithObject:@"agents"];
[doc setAllowedRolesWrite:docReaders];
[doc saveObjCWithLoadAfterwards:true completion:^(NSError * error) {
if(error)
{
...
}
}];

Swift

Swift
var doc = Document()
doc.name = "Secure document! Burn after reading!"
let docReaders = ["agents"]
doc.allowedRolesWrite = docReaders
doc.save { (error) in
if error {
...
}
}

JavaScript

JavaScript
var doc= new Apiomat.Document();
doc.setName("Secure document! Burn after reading!");
var docReaders=["agents"];
doc.SetAllowedRolesWrite(docReaders);
 
var saveCB = {
onOk : function() {
console.log("saved");
},
onError : function(error) {
console.log("Some error occured: (" + error.statusCode + ")" + error.message);
}
};
doc.save(saveCB);

TypeScript

TypeScript
const doc = new Document();
doc.name = "Secure document! Burn after reading!";
doc.allowedRolesWrite = ["agents"];
await doc.save();

Dynamic Roles / custom role check methods

You can also implement your own role check method in one Native Module class and use it for protecting any other of your module classes. If other customers' modules are visible to you because either they granted you the necessary permissions or because the module is released, then you can also use their custom role check methods as well.

Dynamic Roles work similar to the Authentication Classes, but instead of assigning them to the backend, you assign them to classes, so you have a much more fine grained control.

For more information about this feature, see Dynamic Roles.