Skip to main content

Securing MarkLogic Server

JavaScript - Query Element Hierarchies

You can also try these examples demonstrating concealed elements using JavaScript. Using fn.doc() instead of a CTS query to retrieve documents, different users will be able to view (or not view) protected elements. Since there is no query involved, query rolesets are not required.

Use this JavaScript code to insert this document (with permissions) into the Documents database:

// insert document with permissions -> run against Documents database

declareUpdate();
var perms = [xdmp.permission("els-role-1", "read"), xdmp.permission("els-role-2", "read"), 
xdmp.permission("els-role-1", "update"), xdmp.permission("els-role-2", "update")                         
];
xdmp.documentInsert(      
"hierarchy.xml", xdmp.unquote(` 
<root>
 <title>Title of the Document</title>
 <summary>Summary of document contents</summary>
 <executive-summary>Executive summary of the document contents
   <secret>Only role having "secret" can read this
     <top-secret>Only role having "top-secret" can read this
     </top-secret>
   </secret>
</executive-summary>
<content>Contents of document 
  <top-secret>Only role with "top-secret" can read this
     <secret>Only role with "secret" can read this</secret>
  </top-secret>
Unclassified content
</content>
</root>
`), {permissions: perms})

Add protected paths with permissions for roles to the Security database:

// add protected paths -> run against the Security database

declareUpdate();
var security = require('/MarkLogic/security.xqy');

security.protectPath('secret', [], [xdmp.permission("els-role-2", "read", "element")]),
security.protectPath('top-secret', [], [xdmp.permission("els-role-1", "read", "element")])
=>
Returns a number representing the protected paths

Note

Adding, unprotecting, or changing permissions on protected paths will trigger reindexing.

Test this example in the context of the different els-users. This query uses the context of els-user-1:

// run this query against the Documents database

xdmp.eval("fn.doc('hierarchy.xml')", null,
  {
    "userId" : xdmp.user("els-user-1")
  })
=>
<?xml  version="1.0" encoding="UTF-8"?>
<root>
  <title>Title of the Document</title>
  <summary>Summary of document contents</summary>
  <executive-summary>Executive summary of the document contents
   
  </executive-summary>
  <content>Contents of document 
  
  <top-secret>Only role with "top-secret" can read this</top-secret>

  Unclassified content
  </content>
</root>

The “top-secret” role (els-user-1) cannot see the elements marked with “secret”, only those that have no protected paths or marked with the protected path for “top-secret”. Next, run the query in the context of els-user-2:

// run this query against the Documents database

xdmp.eval("fn.doc('hierarchy.xml')", null,
  {
    "userId" : xdmp.user("els-user-2")
  })
=>
<?xml  version="1.0" encoding="UTF-8"?>
<root>
  <title>Title of the Document</title>
  <summary>Summary of document contents</summary>
  <executive-summary>Executive summary of the document contents
   
  <secret>Only role having "secret" can read this</secret>
  </executive-summary>
  <content>Contents of document 
  
  Unclassified content
  </content>
</root>

Notice that even though in the original document, there is an element “secret” within the “top-secret” contents of the document, it is a child of the “top-secret” element and therefore hidden to users without the “top-secret” role.

The els-user-1 (“top-secret”) cannot see the “secret” content unless you add the els-role-2 to els-user-1. When you add the role, els-user-1 will be able to see both the “secret” and “top-secret” elements.

If you run the query as els-user-3, the query returns an empty sequence. The els-user-3 from the previous query does not have permission to even see the document.