Server

File Download Security Policies

Updated: March 18, 2024

Hyland University
Watch the related courses 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 blobs in the Platform. Your security 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 for 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 forbidden by this permission (but other permission rules could forbid it),
  • false means that downloading the blob is forbidden.

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

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: file downloads from the download servlet, Automation, WebEngine, REST API, Seam or Restlets.
    • picture: downloadPicture codec (the XPath is then one of OriginalJpeg:content, Medium:content, Small:content, Thumbnail:content, etc.).
    • thumbnail: downloadThumbnail codec.
    • 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 JSON responses. Includes Automation and 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.

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>