Skip to main content

Securing MarkLogic Server

XQuery - Query Element Hierarchies

Use this code to insert a new document (along with permissions) into the Documents database:

(: insert document with permissions => run against Documents database :)

xquery version "1.0-ml";

xdmp:document-insert(
"hierarchy.xml", <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>,
(xdmp:permission("els-role-1", "read"), xdmp:permission("els-role-2", "read"), 
xdmp:permission("els-role-1", "update"), xdmp:permission("els-role-2", "update")))

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

(: add protected paths -> run against the Security database :)

xquery version "1.0-ml";
import module namespace sec="http://marklogic.com/xdmp/security" 
  at "/MarkLogic/security.xqy";

sec:protect-path("secret", (), (xdmp:permission("els-role-2", "read"))),
sec:protect-path("top-secret", (), (xdmp:permission("els-role-1", "read")))

=>
Returns two numbers 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 first query uses the context of els-user-1:

(: run this against the Documents database :)

xdmp:eval('fn:doc("hierarchy.xml")',(),
  <options xmlns="xdmp:eval">
    <user-id>{xdmp:user("els-user-1")}</user-id>
  </options>
)
=>
<root>
 <title>Title of the Document
 </title>
 <summary>Summary of document contents</summary>
 <executive-summary>Executive summary of 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 against the Documents database :)

xdmp:eval('fn:doc("hierarchy.xml")',(),
  <options xmlns="xdmp:eval">
    <user-id>{xdmp:user("els-user-2")}</user-id>
  </options>
)
=>
<root>
 <title>Title of the Document</title>
 <summary>Summary of document contents</summary>
 <executive-summary>Executive summary of 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.