Access Control and Data Validation for App Endpoints
Access Control and Data Validation is vital to the security of your App Endpoint.
The Access Control and Data Validation function for an App Endpoint can be accessed 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
option.Figure 2. Updating the Access Control and Data Validation functionThe provided Javascript function executes every time a new revision/update is made to a document.
The Capella UI (shown in Figure 2) will check that the JavaScript function is valid when the APPLY button is pressed.
You can restore the function to its original default by clicking RESTORE TO DEFAULT.
The Access Control and Data Validation function
The default function does 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. |
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) {
// ...
}
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"});
}
}