mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
81 lines
4.7 KiB
Plaintext
81 lines
4.7 KiB
Plaintext
[#SecurityKeyTypes]
|
|
== Security Key Types
|
|
include::../variables.adoc[]
|
|
|
|
In QQQ, record-level security is provided by using a lock & key metaphor.
|
|
|
|
The use-case being handled here is:
|
|
|
|
* A user has full permission on a table (query, insert, update, and delete).
|
|
* However, they should only be allowed to read a sub-set of the rows in the table.
|
|
** e.g., maybe it's a multi-tenant system, or the table has user-specific records.
|
|
|
|
The lock & key metaphor is realized by the user being associated with one or more "Keys"
|
|
(as values in their session), and records in tables being associated with one or more "Locks"
|
|
(as values in fields).
|
|
A user is only allowed to access records where the user's key(s) match the record's security lock(s).
|
|
|
|
For a practical example, picture a multi-tenant Order Management System,where all orders are assigned to a "client".
|
|
Users (customers) should only be able to see orders associated with the client which that user works for.
|
|
|
|
In this scenario, the `order` table would have a "lock" on its `clientId` field.
|
|
Customer-users would have a `clientId` key in their session.
|
|
When the QQQ backend did a search for records (e.g., an SQL query) it would implicitly
|
|
(without any code being written by the application developer) filter the table to only
|
|
allow the user to see records with their `clientId`.
|
|
|
|
To implement this scenario, the application would define the following pieces of meta-data:
|
|
|
|
* At the QQQ-Instance level, a `SecurityKeyType`,
|
|
to define a domain of possible locks & keys within an application.
|
|
** An application can define multiple Security Key Types.
|
|
For example, maybe `clientId` and `userId` as key types.
|
|
* At the per-table level, a `RecordSecurityLock`,
|
|
which references a security key type, and how that key type should be applied to the table.
|
|
** For example, what field stores the `clientId` value in the `order` table.
|
|
* Finally, when a user's session is constructed via a QQQ Authentication provider,
|
|
security key values are set, based on data from the authentication backend.
|
|
|
|
=== Additional Scenarios
|
|
|
|
==== All Access Key
|
|
A "super-user" may be allowed to access all records in a table regardless of their record locks,
|
|
if the Security Key Type specifies an `allAccessKeyName`,
|
|
and if the user has a key in their session with that key name, and a value of `true`.
|
|
Going back to the lock & key metaphor, this can be thought of as a "skeleton key",
|
|
that can unlock any record lock (of the security key's type).
|
|
|
|
==== Null Value Behaviors
|
|
In a record security lock, different behaviors can be defined for handling rows with a null key value.
|
|
|
|
For example:
|
|
|
|
* Sometimes orders may be loaded into the OMS system described above, where the application doesn't yet know what client the order belongs to.
|
|
In this case, the application may need to ensure that such records, with a `null` value in `clientId` are hidden from customer-users,
|
|
to avoid potentially leaking a different client's data.
|
|
** This can be accomplished with a record security lock on the `order` table, with a `nullValueBehavior` of `DENY`.
|
|
** Furthermore, if internal/admin users _should_ be given access to such records, then the security key type can be
|
|
configured with a `nullValueBehaviorKeyName` (e.g., `"clientIdNullValueBehavior"`), which can be set per-user to allow
|
|
access to records, overriding the table lock's specified `nullValueBehavior`.
|
|
*** This could also be done by giving internal/admin users an `allAccessKey`, but sometimes that is not what is required.
|
|
|
|
* Maybe a warehouse locations table is assigned a `clientId` once inventory for a client is placed in the location,
|
|
at which point in time, only the client's users should be allowed to see the record.
|
|
But, if no client has been assigned to the location, and `clientId` is `null`,
|
|
then you may want to allow any user to see such records.
|
|
** This can be accomplished with a record security lock on the Warehouse Locations table, with a `nullValueBehavior` of `ALLOW`.
|
|
|
|
=== QSecurityKeyType
|
|
A Security Key Type is defined in a QQQ Instance in a `*QSecurityKeyType*` object.
|
|
|
|
*QSecurityKeyType Properties:*
|
|
|
|
* `name` - *String, Required* - Unique name for this security key type within the QQQ Instance.
|
|
* `allAccessKeyName` - *String* - Optional name of the all-access security key associated with this key type.
|
|
* `nullValueBehaviorKeyName` - *String* - Optional name of the null-value-behavior overriding security key associated with this key type.
|
|
** Note, `name`, `allAccessKeyName`, and `nullValueBehaviorKeyName` are all checked against each other for uniqueness.
|
|
A `QInstanceValidationException` will be thrown if any name collisions occur.
|
|
* `possibleValueSourceName` - *String* - Optional reference to a possible value source from which value for the key can come.
|
|
|
|
|