Configure Access Control and Data Validation
- Capella Operational
Access Control and Data Validation is vital to the security of your App Endpoint.
Concepts
The Access Control and Data Validation function allows you to configure document access or validate document data with Scopes and Collections, facilitating Role-based access control (RBAC).
You can customize the Access Control and Data Validation function for every linked collection within a given scope.
The Access Control and Data Validation function is performed on every document write to the associated linked collection.
Procedure
You can access the Access Control and Data Validation function for an App Endpoint through the App Endpoint’s configuration screen:
-
From the App Services screen, you can select the App Endpoints tab.
Figure 1. Select App EndpointThe next screen will allow you to configure the endpoint.
-
Select the App Endpoint you wish to configure the Access Control and Data Validation function for.
Figure 2. Select Linked Collections -
Select the linked collection you wish to configure the Access Control and Data Validation function for.
-
Define your Access Control and Data Validation function.
Figure 3. Updating the Access Control and Data Validation FunctionThe provided Javascript function executes every time a new revision/update is made to a document.
Couchbase recommends thoroughly checking the validity of the function as it will affect each documents' operations that are passing through an App Endpoint. You can restore the function to its original default by clicking Restore to Default.
The Access Control and Data Validation Function
The default function performs no validation; it simply assigns the document to the channels specified in its 'channels' attribute.
function (doc, oldDoc, meta) {
channel(doc.channels);
}
The function arguments are:
Name | Description |
---|---|
|
This object references the content of the document that is being saved. It matches the JSON saved by the Couchbase Lite application and replicated to the App Service. The document’s |
|
If the document has been saved before, this object references the revision being replaced; otherwise it is null. |
|
This argument references the user defined XATTR that you can use to hold access grant data. The referenced object can include items such as channels or roles. So, instead of embedding channel information directly within the document body, users can specify the user-defined XATTR associated with the document. |
The default function differs depending on the following situations:
|
Writing a Custom Access Control and Data Validation Function
Consider your access control and document distribution requirements. For example:
-
The document types it will process
-
The users it will serve
-
Which users need to access which document types
-
What constraints are to be placed on creating, updating and/or deleting documents.
This example demonstrates a number of possible use-cases that may be useful to you. Start by creating your function as usual:
function (doc, oldDoc, meta) {
// ...
}
The following example defines channel settings with the content of an XATTR:
function (doc, oldDoc, meta) {
if (meta.xattrs.channelXattr === undefined)
{
console.log("no user_xattr_key defined")
channel(null)
} else {
channel(meta.xattrs.channelXattr)
}
The meta parameter exposes the user defined user_xattr_key
if it is defined, and uses the content of the XATTR to define the channels
setting for the document.
Handling Deletion
In this example, we require the user to:
-
have the Editor role
-
be one of the original writers of the document.
if (doc._deleted) {
requireRole("role:editor");
requireUser(oldDoc.writers);
// Skip other validation because a deletion has no other properties:
return;
}
Handling Required Properties
In this example, we:
-
require the properties: 'title', 'creator', 'channels', 'writers'
-
expect the 'channels' and 'writers' properties to be lists, and require the 'writers' list to be non-empty.
if (!doc.title ||
!doc.creator ||
!doc.channels ||
!doc.writers)
{
throw({forbidden: "Missing required properties"});
}
else if (doc.writers.length == 0) {
throw({forbidden: "No writers"});
}
Handling Creation
If oldDoc
is not passed to the function, then a new document is being created.
In this example, we:
-
require the user to have the 'editor' role
-
require the user to match the original 'creator' of the document.
if (! oldDoc) {
requireRole("role:editor");
requireUser(doc.creator)
}
Handling Modification
If oldDoc
is passed to the function, we know that document is being modified.
In this example:
-
Only users in the existing doc’s writers list can change a document
-
The 'creator' property is immutable.
if (oldDoc) {
requireUser(oldDoc.writers);
if (doc.creator != oldDoc.creator) {
throw({forbidden: "Can't change creator"});
}
}