orb » data modelling

Secure your data with role-based access control. A role is set by your application at run-time, and dictates which operations and data the run-time may access. orb has machinery for auditing roles to see all data and operations they may access.

The foundation of auditing is the role, which defines a run-time role, for example, a user, administrator, mailer, etc. Auditing is the process of examining which roles map to which operations.

In orb, roles are hierarchical: a role inherits the permissions of its parent. This models the usual behaviour of application systems where roles follow authentication, and transition from fewer to greater permissions.

Role transitions may occur downward into roles of greater specificity and laterally only from the system default, which is the initial role and universal source; and into the none role (not shown), which is the universal sink and may not be transition from (not shown).

In this example, the data model consists of user-defined roles prelogged (for users who have connected to but not authenticated wit the system); admins and users, for users who have authenticated according to a request type; admins-smtp, for administrators who can administer SMTP server data; and mailer, which is unauthenticated and runs the e-mail service.

Functionally, the prelogged role may only have access to the operation for checking login credentials and nothing more. The users would contain all data and operations for usesr, while admin would transition into specific administrative purposes—perhaps dictated by path or administrator attributes.

Roles are created and assigned when editing a data model. Each field and each operation may be mapped to zero or more roles, which restrict or enable the component, respectively.

In orb, roles are created and assigned when editing data models. Each component assigned is also inherited by the role's children.

Creating and modifying roles hapens in the data model editor. Roles may be added within the hierarchy, or changed within the hierarchy.

Once created, roles may be assigned to operations and data. In the case of operations, roles assigned to operations are allowed to make those operations—any other role attempting the operation will fail (the run-time). For data, data assigned to roles as not exporting are not exported from the application. Thus, the application may make use of the data, but is not allowed to export it. If not assigned, it may export it.

Thus, operations are default-deny and data are default-allow. This discrepency is because in practice, most data is shared across roles, while most operations are not.

Once the roles are created and provisionally assigned, the assignments may be audited in the orb auditor.

The mapping of roles to data and operations may be seen at a glance in the orb auditor, which examines all possible data access, even if indirectly by way of foreign keys.

A powerful auditor is necessary as data models grow in complexity: it becomes increasingly difficult to be certain that a given role only has access to what it needs.

The auditor is available to any data model with roles created. It breaks down a data model by data (structures) and operations (queries, updates, …). In the default structure view, each structure is shown with a quick view on the percentage of exported fields followed by the number of operations for the given role.

Clicking on a given struture shows all of its fields and available operations. By clicking on any field or operation, all possible paths to get to those fields is shown—for example, a field may be accessed through a query on another structure that has a foreign key reference to the current structure.

The per-operation view simply lists all operation types and the operations in that type that may be invoked by the role.

Once configured, the actual choice of role to a run-time occurs in a running application.

Operating roles from the source code generated by orb is very easy. Roles are bound to a context opened up per connection, allowing, for instance, a web application to handle roles on a per-connection basis.

The following example follows the simple example from the code generation tutorial. The data model code is downloaded using npm, and the web application configured with express.js. The application should be configured with a role users, which is allowed to insert new users and to run the query for getting a user by its identifier.

import express from 'express';
import { ort, ortns, ortctx, ortdb } from '@orb/1234-5678/ort';

const app: express.Application = express();
const db: ortdb = ort('ort.db');

app.get("/put", 
  function(req: express.Request, res: express.Response) {
    const ctx: ortctx = db.connect();
    ctx.db_set_role('users');
    const id: bigint = ctx.db_user_insert('new user');
    return res.send(id.toString());
  }
);

app.get("/get",
  function(req: express.Request, res: express.Response) {
    const ctx: ortctx = db.connect();
    ctx.db_set_role('users');
    const user: ortns.user|null = ctx.db_user_get_id(BigInt(1));
    if (user === null)
      return res.status(404).send('not found');
    return res.send(user.obj.name);
  }
);

app.listen(3000, function() {
  console.log('Server is running.');
});

The special function here is db_set_role, which sets the role conditional upon the current role. Roles can only descend their hierarchy or traverse into the none role.