Access Control
DRAPI follows Domino's access control, there's no sidestepping. You can however tighten the screws to be very specific on individual access requirements.
Access Annotations
You can decorate each request class with a series of Java annotations to both document and early enforce access requirements:
@MinimumAcl(AclLevel)
- specify the required ACL access. While e.g. Editor access suffices for updating a document, you can specify that this function requires Designer access@AclAttributes(AclAccessFlags)
- require specific flags likeCreateDocuments
orCreateSharedFoldersViews
, all the checkboxes in the ACL@AclRoles(String[])
- User must have one of the roles to perform the operation@ServerAclSecurity(ServerAclType)
- required Server ACL entries likeSERVER_ADMIN
,FULL_ADMIN
,DATABASE_ADMIN
and more@ServerEclSecurity(ServerEclType)
- required execution permissions likeRUN_UNRESTRICTED_CODE
,RUN_RESTRICTED_CODE
andRUN_FORMULA
So your class could look like this:
@MinimumAcl(AclLevel.AUTHOR)
@AclAttributes({AclAccessFlags.CreateDocuments})
@AclRoles({"Approver"})
public class SubmitDecision extends AsyncDominoJNXJson {
public void process(final DbRequestParameters<JsonObject> request) throws Exception {
request.validate();
// Your code goes here
}
}
Helper methods
There are a number of helper methods available to perform common checks. Most of them can be found in the KeepJnxSession
, or as static methods in DocumentFunctions
check the JavaDoc for details:
Optional<Document> session.getDocumentByUNID(request.db, unid, DocumentScope.VALID_DOCUMENTS_ONLY)
Document validateDocumentAccessRequest(final Database db, final String unid, final DocumentAccess docAccess, final Optional<KeepRequestId> requestId)
Document createDocFromJson(final Database db, final JsonObject body)
void updateDocumentFromJson(final JsonObject jsonSource, final Document doc)
JsonObject DocumentFunctions.document2Json(doc, includeMeta)
Typical code pattern would look like this:
// Get a specific document
final Optional<Document> optionalNote = request.session.getDocumentByUNID(request.db, unid, DocumentScope.VALID_DOCUMENTS_ONLY);
// Throw an error
final Document note = optionalNote.orElseThrow(() -> new KeepExceptionNotFound(KeepExceptionStrings.NO_DOCUMENT_ACCESS, unid));
// Create a new doc
final Document note = optionalNote.orElse(() -> db.createDocument());
Priviledged operations
A typical requirement in web applications is the need for operation specific elevated priviledges. E.g. you want the default access for "ApprovalLog.nsf" to be Reader,
so nobody can manually create or alter documents, but the code in SubmitDecision
needs to be able to create. For this scenario, the KeepJnxSession
allows to execute
operations as the server, using server privileges.
The modified code from Business Logic would look like this:
try (KeepClient kc = request.session.getClientAsIDUser(); // Session as server
Database approvalLog = kc.openDatabase("ApprovalLog.nsf")) {
// Write to log
Document logEntry = approvalLog.createDocument();
logEntry.replaceItemValue("Form", "logentry");
// like before
logEntry.save();
// Update document
// like before
doc.save();
} catch (Exception e) {
logger.error(e.getMessage());
throw e;
}
With great powers...
...come great responsibilites. While this allows to have tight access control, it can backfire when not implemented carefully
Next
Let's connect
We really like to hear from you!
Your opinion matters. Let us know all your:
- questions
- discussions
- ideas
- feedback
Join the OpenNTF Discord channel.