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.
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.