Let's talk
engineering

Staff who can see invoices should not mark them paid

Two hard-coded roles made everyone an administrator. How 77 permissions replaced them, and the bug that nearly showed field staff the director's screen.

· · updated

A director at a desk reviewing the list of boards in Sazinga AdBoard on a monitor.

Your software knows two kinds of person, owner and employee. Your bookkeeper needs to see invoices, but should not be able to mark one as paid. Your field staff need to see bookings, but not the director’s figures. The software cannot express either, so the only way to let people do their jobs is to make them all administrators.

That was the state of the operations system we built for Gold Sign Media, an outdoor-media business. Every core part of the system was behind a check for “owner”. In practice, an employee could not use any core business function at all. That is where every two-role system ends up. The permissions stop being a control and become a formality, and anybody with a login can change anything.

What was actually going on

The two roles started as a reasonable simplification. They did not match how the business divides its work, and the only way round was to hand out the higher role more widely.

The rebuild replaced them with roles assembled from around 77 separate permissions across 19 areas of the system. A person can hold more than one role, and what they may do is the combination. Two decisions made it work.

The permissions include business actions, not just create, read, change and delete: turning a proposal into a booking, recording a payment against an invoice, working out a partner payout. Someone who can edit an invoice is not necessarily someone who may mark it paid, and someone who can prepare a payout run may not be the one who releases it. If permissions only cover editing, the business’s real distinctions end up buried somewhere else, in a status field or an approval table, where the permission screen cannot see or change them.

The permissions themselves are fixed in the system’s code, and administrators create and edit roles, never permissions. A permission means something only because some part of the system checks it. One an administrator could invent on a screen, checked by nothing, would be a control that does nothing, and would be given to someone who then believes they have access they lack. Combining existing permissions into new roles is what an administrator should be able to do.

What we changed

What a person may do is looked up on each request, not stored in their login. The login lasts about a month. A permission list stored in it would go stale the moment an administrator changed a role, so taking someone’s access away would not take effect until the login expired, which defeats the point of taking it away. A short-lived copy with a clear way of expiring it gives most of the speed and none of that problem.

Two faults turned up on the way, and both are worth learning from.

The mobile app chose between the manager’s view and the field view by asking whether the user could view invoices or proposals. It looked sensible. But the operations role legitimately held both, because operations staff need to see bookings and their paperwork, so field staff would have been shown the director’s dashboard. The lesson we wrote down is that being able to see money is not authority over it. A screen that stands for a level of responsibility should be gated by a permission that means that responsibility, not by a mix of viewing permissions that happens to line up with it today. Where no such permission exists, add one.

The permission editor had a fault of its own. The list of permissions sent to it used one set of field names and the editor read another, so every tick box shared the same identifier and ticking one ticked them all. It was not a security hole, because the system checked properly. But an editor that cannot express a choice is a permission model nobody can configure, which is the same as having none. It was fixed by correcting the list once, at the point where it enters the editor.

One more decision needs stating. Where a person lacks permission to see financial figures, the system leaves that section out of what it sends to the device. Hiding something on screen is a presentation choice. Leaving it out is a security control, because only that stops the data reaching the device. The menu is a different matter: showing every menu item and politely refusing the ones a person may not use is a fair choice for non-sensitive areas, because people can see what they could ask to be given. Hide the data, not necessarily the menu.

What it did not fix

Having fine-grained permissions does not choose who should hold them. Somebody still has to decide what a bookkeeper may do, and a generous role is still generous. The permission editor’s fault shows how fragile the controls are at the edges: the checking was sound, but the tool for setting it up was not, until it was fixed.

The pattern, for anyone whose staff all have the same access

Ask of your current software: can I give a person the ability to see an invoice without the ability to mark it paid? Can I give a manager everything in their branch and nothing in another? Can I take access away and know it took effect today?

If any answer is no, people are working around the software, and the usual workaround is to make them administrators. The test for any screen that represents a level of authority is whether it is gated on a permission that means that authority.

Where this ends up

The permission model described here is the one behind Sazinga AdBoard, where permissions cover actions such as proposal-to-booking conversion and partner payouts, and roles are built from them.

This came out of building Sazinga AdBoard

Every site, every booking, every invoice — in one place. The problem above is one we met while building it, and what we did about it is in the product.

If you run something like this, there is one thing you can do without a call: tell us your board count.