Security

File Download Security Policies

Updated: July 17, 2023

 

Extract from the course What's New in Nuxeo Platform 2015 on Hyland University

In addition to the permissions applying to a document, which restrict access to a document as a whole, it's possible to specify more fine-grained permissions to disallow the download of some file attachments.

 

If you are looking to dynamically restrict access to whole documents depending on a set of conditions and not to its attachments only, you should have a look at the Security Policy Service documentation.

File download security policies apply to all files in the Platform. Your filters need to be specific enough in order to avoid possible side-effects. Make sure to use the available variables at your disposal to check you are in the right use case first.

Possible side-effects you may want to check include:

  • Show graph feature in a workflow
  • User suggestion widget, for instance in the admin tab, users & groups menu, when editing the groups a user belongs to.

Download Permissions

To additionally restrict the download of a given blob inside a document, you can contribute to the following extension point:

   <extension target="org.nuxeo.ecm.core.io.download.DownloadService" point="permissions">
    <permission name="myperm">
      <script language="JavaScript">
        function run() {
          if (CurrentUser.getName() != "bob") {
            return false;
          }
          return true;
        }
      </script>
    </permission>
  </extension>

The above is an example script that will prevent download if the user is not "bob".

The language can be any JVM scripting language, the default is "JavaScript".

The <script> must define a run() function that returns a boolean:

  • true means that downloading the blob is not disallowed by this permission,
  • false means that downloading the blob is forbidden.

The run() method will get called with the following global context (some values may be null for non-standard download methods):

  • Document (DocumentModel): the document in which the blob is stored. This may be null for dynamically computed dowloads (ZIP exports, EL, Automation results).
  • XPath (String): the xpath at which the blob is stored in the document. This may be null if there is no document (see above), or if the blob was not stored in the document but just computed from it (renditions, thumbnail).
  • Blob (Blob): the blob itself.
  • CurrentUser (NuxeoPrincipal): the current user.
  • Reason (String): the download "reason", which gives an indication of the source of the download:
    • download: basic servlet download, restlet download or documentActions.download.
    • picture: downloadPicture codec (the XPath is then one of OriginalJpeg:content, Medium:content, Small:content, Thumbnail:content, etc.).
    • thumbnail: downloadThumbnail codec.
    • clipboardZip: worklist ZIP export.
    • workListXML: worklist XML export.
    • pdfConversion: PDF conversion.
    • el: EL-triggered download.
    • operation: Automation operation (WebUI.DownloadFile / Seam.DownloadFile).
    • rendition: rendition.
    • templateRendition: template rendition.
    • webengine: WebEngine blob responses. Includes REST API calls.
    • contentDiff: content diff display.
    • tile: image tiling display.
    • preview: preview display restlet.
  • Rendition (String): the rendition name, if this is a rendition.
  • Infos (Map): the ExtendedInfos map passed internally to the download method.

If there are several permissions defined, a single one returning false is sufficient to forbid the blob download.

Example

Here is a more complex (if unrealistic) example that uses most of the available context variables:

  <extension target="org.nuxeo.ecm.core.io.download.DownloadService" point="permissions">
    <permission name="myperm">
      <script>
        function run() {
          if (CurrentUser.getName() != "bob") {
            return false;
          }
          if (!CurrentUser.getGroups().contains("members")) {
            return false;
          }
          if (Document.getPropertyValue("dc:format") != "pdf") {
            return false;
          }
          if (Reason != "rendition") {
            return false;
          }
          if (Rendition != "myrendition") {
            return false;
          }
          if (Blob.getFilename() != "myfile.txt") {
            return false;
          }
          if (XPath == "file:content" || XPath == "blobholder:0") {
            return false;
          }
          return true;
        }
      </script>
    </permission>
  </extension>

Debugging

If you launched your Nuxeo instance in console mode (./nuxeoctl console), you can print output to the terminal for easier debugging. For instance, getting the available variables is done as following:

<extension target="org.nuxeo.ecm.core.io.download.DownloadService" point="permissions">
  <permission name="myperm">
    <script language="JavaScript">
      function run() {
        print("doc " + (Document == null ? "null" : Document.getId()));
        print("filename " + (Blob == null ? "null" : Blob.getFilename()));
        print("xpath " + XPath);
        print("user " + CurrentUser.getName());
        print("reason " + Reason);
        print("rendition " + Rendition);
        return true;
      }
    </script>
  </permission>
</extension>