Gyroscope / User Access Control
Gyroscope uses a cookie-based system to authenticate users. Each user is
described with a list of capabilities, which is then used by specific
In simple terms, here's what happens internally when user Bob signs in with
his password "bob123":
compares the hash of Bob's password against an internally
stored hash to determine whether the passwords match. Upon successful
authentication, a set of cookies are placed. One of these cookies indicates
Bob's capabilities, for instance "billing" and "reporting".
Bob's further interaction with the system no longer results in database
queries. The server side script utilises functions in auth.php to determine
whether Bob has already signed in and whether he has access to billing or
To redirect a user to a login page if he hasn't signed in:
To silently fail a user request:
To obtain user info:
To check the billing flag:
//billing specific code here
Note that the group names are arbitrary. They can be used to implement a
role-based access control system or clearance-level based security, or a
system that's fine grained such that a user can view and modify a record but
not delete it. It's up to the application developer to design a secure and
managable access control system.
Now that we know how to use authentication and access control in
Gyroscope, let's look at how the system handles to security issues that come
with cookie-based systems.
- Cookies can be forged
- Cookies can be stolen
- Cookies can be outdated
To prevent cookie forgery, we also store a validation hash as a cookie. By
default, this hash uses a salt that's defined in auth.php and contains the login,
userid and groups. If any of these values are tempered, the cookie will fail to
Starting Version 9.6, each service request is checked against a list of inactive users.
This allows immediate access denial to selected users.
Instant eviction can be optimized by uncommenting the memcache related lines in evict_getblockedids
gsid and gsguard
Starting Version 12.5, access to records can be partitioned by "gs instances" that are identified by "gsid". It is the
developer's responsibility to ensure that the gsid field is in each table that corresponds to a base record. For example,
in a database of cars where a car is a base record, the cars
table should have a gsid
field. However, a subordinate table,
, does not need a gsid.
The gsid can be retrieved from the authenticated user context:
Base record tables can then be authenticated as such:
$query="select * from cars where ... and gsid=$gsid";
A utility function, gsguard
, can be used to regulate access to sub records.
Here is a trivial use case that ensures that the carid
is linked to an authorised car record:
Internally, the following query is built to enforce access:
select cars.carid from cars where cars.gsid=$gsid and cars.carid=$carid
In a more complex scenario, where cars, carparts and partattributes form a 1-N chain, the entire chain can be authenticated:
The above function call effectively checks the credentials against the following query:
array contains field names of connecting keys, separated by dashes (-).
The last element of the keys
array is the exit field that matches the input parameter, typically obtained by GETVAL/QETVAL.