1
votes

Can you please guide me on how to set up read only access at database level in MarkLogic. For every document in database, I have set up an access as below

<sec:permission xmlns:sec="http://marklogic.com/xdmp/security">
<sec:capability>read</sec:capability>
<sec:role-id>rest-reader</sec:role-id> 
</sec:permission>

<sec:permission xmlns:sec="http://marklogic.com/xdmp/security">
<sec:capability>update</sec:capability>
<sec:role-id>rest-writer</sec:role-id>
</sec:permission>

But still from ML console, I am able to delete such documents. User which I used to login to Query console, does not have rest-writer access.

Please let me know if more details are required. Thank you.

2
There is no such thing as read-only access at a database level. What are all of the roles (direct and inherited) for the user you are using in query console? - David Ennis
Hi David, Thanks for your comment, I tried to extract, roles for logged in user on query console, only role assigned to this user is rest-reader. I removed this role as well but still I am able to delete documents. - Shrikant Lohiya

2 Answers

2
votes

If you have an explicit read permission for every document in the database, you should be able to grant your QConsole read-only users just the qconsole-user and rest-reader roles.

Granting qconsole-user gives them access to QConsole, and granting rest-reader will give them read access to those documents.

Removing the rest-reader role would leave the user with only the qconsole-user role and would prevent the user from seeing any of those documents in the content database with those explicit permissions.

Additional roles may result in other permissions and behaviors, but with just those two roles the user should only be able to read the documents and would be prevented from writing.

If your users are able to delete those documents, then they likely have other roles and permissions granting those rights.

To demonstrate, run the following against the Security database and then test logging in as this read-only-user in QConsole and attempt to delete one of those documents:

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

sec:create-user(
    "read-only-user",
    "A test user demonstrating read-only access",
    "password",
    ("qconsole-user", "rest-reader"), 
    (), (), ()
  )
0
votes

Mads Hansen gave a great example to demonstrate the user permissions and a test to ensure that you can see how a user can be given limited access to read documents AND also use the query console - an important set of permissions for users to explore the data. However, based on your reply to my original comments, I think an exercise in understanding how to find the access to the documents and user is important in troubleshooting.

Please see the following script. It must be run as an admin user or one that has the execute privilege 'user-get-roles' and likely 'xdmp-invoke-function'

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

let $sec-db := xdmp:security-database()
let $uris := cts:uri-match('*')[1 to 20]
let $user := 'test-a-user'

(: run on the security database :)
let $role-report := xdmp:invoke-function(function(){
    let $direct-roles := xdmp:role(sec:user-get-roles($user))
    let $roles := (xdmp:role-roles(sec:user-get-roles($user)), $direct-roles)
    return <roles>{
      for $role-id in $roles
      return element {'role'} {
        attribute {'id'} {$role-id},
        attribute {'directly-attached'} {if ($direct-roles = $role-id) then '1' else '0'},
        xdmp:role-name($role-id)
      }
    }
    </roles>
  }, <options xmlns="xdmp:eval">
      <database>{$sec-db}</database>
    </options>
)

let $doc-report := <doc-access>
  {
    for $uri in $uris
      return for $permission in xdmp:document-get-permissions($uri)
        where $permission/*:capability = 'update' and $role-report//role/@id = $permission/*:role-id
        return <match uri='{$uri}' capability='update'>{xdmp:role-name($permission/*:role-id)}</match>
  }
  </doc-access>

return element {'report'} {
  if($role-report//role/text() = 'admin')
    then element {'attention'} {'Admin role found - access to all documents'}
    else (
      $role-report,
      $doc-report
    )
}

Fill in the user name in question and a sequence of URIs (I just grabbed 20 in my sample)

If any direct or inherited role of admin will cause the following report:

<report>
    <attention>Admin role found - access to all documents</attention>
</report>

Otherwise, you get back a report of all roles for that user (direct or inherited) and all uris with update access (and the matching role). This should be enough for troubleshooting permissions - especially on inherited permissions. It is not production code. You can also modify it to look for read or execute if needed. It also is an example of using some items from the sec namespaced functions.

<report>
  <roles>
    <role id="15240420431168313686" directly-attached="0">test-b</role>
    <role id="7089338530631756591" directly-attached="0">rest-reader</role>
    <role id="13041542794130379697" directly-attached="0">rest-extension-user</role>
    <role id="15520654661378671735" directly-attached="0">rest-writer</role>
    <role id="15240420431090884371" directly-attached="1">test-a</role>
  </roles>
  <doc-access>
    <match uri="/foo/bar.xml" capability="update">test-b</match>
  </doc-access>
</report>