Skip to main content

Securing MarkLogic Server

JavaScript - Matching by Paths or Attributes

This next example shows how protected paths can be used with fn.contains() and fn.matches(). The example uses the same roles from the previous example, adding a new role (els-role-3).

First unprotect the protected paths from the previous example:

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

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

security.unprotectPath('secret', []),
security.unprotectPath('top-secret', [])

Note

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

Create a new role els-role-3 and add els-user-3 to the role. See Create Roles and Create Users and Assign Roles for details.

Add a new document to the Documents database:

// insert document and permissions -> run this against the Documents database

declareUpdate();
var perms = [xdmp.permission("els-role-1", "read"), xdmp.permission("els-role-2", "read"), 
xdmp.permission("els-role-3", "read"), xdmp.permission("els-role-1", "update"), 
xdmp.permission("els-role-2", "update"), xdmp.permission("els-role-3", "update")  
];
xdmp.documentInsert(
"attributes.xml", xdmp.unquote(`
<root>
  <title>Document Title</title>
  <summary>Summary of document contents</summary>  
  <executive-summary>Executive summary of contents
    <info attr="EU">Only role with "EU" attribute can read this summary </info>
    <info attr="UK">Only role with "UK" attribute can read this summary </info>
    <info attr="US">Only role with "US" attribute can read this summary </info>
  </executive-summary>
  <content>Contents of document
  Unclassified content
    <notes> 
    <info attr="EU">Only role with "EU" attribute can read this content</info>
    <info attr="UK">Only role with "UK" attribute can read this content</info>
    <info attr="US">Only role with "US" attribute can read this content</info>
    </notes>
  </content>
</root>
`), {permissions: perms})

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

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

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

security.protectPath("//info[fn:matches(@attr, 'US')]", [],[xdmp.permission("els-role-1","read", "element")]),
security.protectPath("//info[fn:matches(@attr, 'UK')]", [],[xdmp.permission("els-role-2", "read", "element"), 
  xdmp.permission("els-role-3", "read", "element")]),
security.protectPath("//info[fn:matches(@attr, 'EU')]", [],
  [xdmp.permission("els-role-3", "read", "element")])

=>
Returns one number representing the protected paths

Note

Adding or changing permissions on protected paths will trigger reindexing.

Run the same queries as before, first in the context of els-user-1, who has a role that can see the “US” attribute:

// run this query against the Documents database

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

Next modify the query to run in the context of els-user-2, who has a role that can see the “UK” attribute:

// run this query against the Documents database

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

And finally modify the query to run in the context of els-user-3:

// run this query against the Documents database

xdmp.eval("fn.doc('attributes.xml')", null, 
  {
    "userId" : xdmp.user("els-user-3")
  });
=>
<?xml  version="1.0" encoding="UTF-8"?>
<root>
  <title>Document Title</title>
  <summary>Summary of document contents</summary>
  <executive-summary>Executive summary of contents
  
  <info attr="EU">Only role with "EU" attribute can read this summary</info>
  <info attr="UK">Only role with "UK" attribute can read this summary</info>
  </executive-summary>
  <content>Contents of document 
  Unclassified content 
  <notes>
  <info attr="EU">Only role with "EU" attribute can read this content</info>
  <info attr="UK">Only role with "UK" attribute can read this   content</info>
  </notes></content>
</root>

The els-user-3 has protected path permissions on both elements with the “EU” info attribute and the elements with the “UK” info attribute. This way, the user can see both elements.

Note

If you run the query in the context of the admin user, you will be able to see the entire document because the query is using fn.doc().