Storage and flexibility of document rights

Hi everyone,

this is another proposal regarding an aspect of document rights. Document rights are trying to solve the problem that the rights of “active content” in a page like script macros or script extensions only depend on the last author. This makes it easy to accidentally remove or grant rights when the author or the author’s rights change. The idea of document rights is to improve this situation by explicitly specifying what rights a document has and doesn’t have. Editing would then be restricted to users with the specified right(s), and regardless of the last author, nothing in the document can have more rights than specified in the document.

The question I want to answer with this proposal is what such a “right” is in the context of document rights. The initial implementation just uses a Right but in my opinion this misses an important use case: many objects that are active on the whole wiki like translations or UIX require admin right not on the document itself but on the wiki. From my point of view, the primary use cases for now are:

  • Script right
  • Wiki admin right
  • Programming right

In the case of the required rights analyzer, we had the same problem and chose a combination of a right and an entity type as solution. So for example, you have Right.ADMIN, EntityType.WIKI for wiki admin. This could be a solution here, too.

Alternatively, we could also just say that “admin” right is a special case and we always check that on the wiki.

A different option could be to have a mechanism where extensions can register custom document rights that are represented as string constants, with the mentioned three values registered by default.

I can also see some more advanced use cases for document rights:

  • The PDF Viewer Macro (Pro) has a parameter “asauthor” that uses the view right of the author on the PDF file to display it. This could be represented as a required view right on the PDF file.
  • A script using $doc.saveAsAuthor() could use an edit right on the target document.
  • A script displaying a document could use a view right on the displayed document.

Apart from the first case, I have no idea how this could/should work as usually the target pages are dynamic. However, I think for the first use case document rights could be very interesting as in that case you would certainly want to avoid that somebody who cannot view the PDF file edits the page.

For such advanced use cases, it could be interesting to use a combination of a right and an entity reference as document right. To keep this usable, we could offer checkboxes for all right/entity reference combinations that a required right analyzer detected and offer the option to add arbitrary right/entity reference combinations only to advanced users.

To make sure that this stays somehow sane I would say that any such “delegated” right check shouldn’t take document rights into account. So when you say that document A has edit right on document B, to check if user U can edit A, we would only check if U has in principle edit right on document B, not if U also fulfills the document rights on B. Further/alternatively, we could exclude edit right from the rights that can be configured as document rights.

What I’m not sure about is the impact on the security cache as this could add arbitrary cross-dependencies between security cache entries. I think it should be possible, but it would certainly make an already difficult data structure more complex.

Regarding the security cache, I think we could have an access entry without document rights and then when necessary a child entry that takes document rights into account. That child entry with document rights could have other access entries (without document rights) as parents to take their rights into account, thereby ensuring that we get no dependency cycles. Further, to properly represent the notion that document A has right X on document B I think we basically need to treat document A similar to how we currently treat users.

In general, I tend to imagine document rights as being similar to making it possible to assign rights to a document in the same way as we currently assign rights to a user. Except that storing them in the same way would make things super complicated as I feel you should be able to indicate in an extension that a document should have admin right on the wiki for example without adding a right object on the global configuration. But maybe that’s also the right way to store them and we just need to find better ways to distribute them?

To summarize, I see three options:

  1. Do the same as for required rights, each document right is a right and an entity type, allowing values like “Wiki admin”.
  2. Really just use a Right and ignore the wiki admin use case or interpret admin right as wiki admin right.
  3. Use custom values that can be extended by extensions.
  4. Each document right is a pair of a right and an entity reference.

To me, option 4 offers most flexibility but is also most complex and could offer unintended features. For example, I noticed that document rights offer a way to specify that a document can only be edited by wiki admins. With arbitrary entity references and rights, edit rights of document A could even be tied to edit right to document B. I’m not sure whether that’s a good idea.

Option 1 would be consistent with document rights and cover the use cases we care about most. Option 3 sounds like it would offer good extensibility, but I’m not sure if that’s necessary.

Overall, I think I’m +1 for option 1, but I also fear we might be missing an opportunity to express more complex things where we’re using the author’s rights on other entities. If it wasn’t for the complexity, I think I would be for option 4. Option 2 is probably easiest to implement but also sounds like a hack.

Thank you very much in advance for your opinions and suggestions.

Thinking about this again, I’m wondering if introducing another right for wiki admin wouldn’t be another option that could simplify this. Admin right on wiki level is really something different from admin right on the space level I think, for example, you cannot have a UIX on a space, but you can have a UIX on wiki level.

On the other hand, I’m also not sure where this right would be used. My idea would be kind of that this new right would be the right to author code and UI elements that are active on the whole wiki, basically a “global script” right. Though then again, you don’t need to use scripts in a UIX, you can have a UIX with just a bit of text or a non-script macro. Translations are normally not script-related, too, and still need wiki admin right for wiki scope.

In an attempt to get some feedback, I would like to revive this discussion. To summarize my question, how do we store document rights? We need to support the following values initially:

  • script right
  • programming right
  • admin right on wiki level (not on the page/space itself)

It would be good if we could support other rights as well without changing the storage format. The existing required rights analyzers use a combination of Right and EntityType to express this. Should we use the same here, or should we use a combination of Right and EntityReference to make this even more flexible?

I would also like to get your opinion on the implementation of the actual storage of document rights. The storage consists of two parts

  1. A flag to indicate if document rights are enabled on each document. I think this flag should be in the actual document and not, e.g., in an XObject to avoid having an XObject on every document.
  2. The actual rights, for this the first pull request introduced a new database table. I’m wondering if we shouldn’t instead extend the existing XWiki.RequiredRightClass. The arguments for this are the following:
    • This XClass was meant for exactly this purpose as, e.g., documented in issue XWIKI-7879.
    • We don’t need to add more complexity to the document’s storage.
    • Most pages still won’t need this extra XObject as they won’t contain scripts or other content that requires special rights.
    • We won’t have two ways to indicate required rights (the XClass and the rights stored in the document).
    • Easier migration path for extensions as they could start adding the XObject before they depend on an XWiki version with the feature.

Any opinions on this?

+1

Note that while it’s true for the xobject, my understanding is that you also need to set the document field to enable that (unless the plan is that it’s enabled also if there is a required right xobject ?), and:

  • it will produce a warning if you import such a document XML in a version of XWiki which does not understand this field
  • more importantly, it won’t be enabled if you already installed your extension before upgrading to a version of XWiki which understand this field

Other things to probably do:

  • ideally the XWiki.RequiredRightClass should be moved to a class initializer component instead of a page provided by xwiki-platform-distribution-ui-base, since it would become much more core
  • at some point, we might want to start checking in the Maven XAR plugin that all pages have the required right enabled. It’s definitely a lot of work to do that for all XWiki Standard pages, but I think we’ll want to reach this point ASAP once we have the feature.

To address the first point, maybe we can include some other metadata in the XAR to indicate that document rights should be enabled on all documents in the XAR regardless of the flag? Then you could include the XObjects without the flag.

For the second point, we could write a migration to detect such extension pages when the wiki is upgraded.

Good points, thank you for the suggestions.

It’s not a concept (have stuff in the extension descriptor impacting how a document is parsed in a XAR) which exist yet, but that could be doable.

We could indeed have a migration checking for extensions having the flag mentionned above if we were to go in that direction.

While starting the implementation, I noticed that the storage location has some important consequences for translated documents. In the following, I list the different possibilities with pros and cons:

  1. Store the actual required rights in XObjects but the “enabled” flag in the document itself - current proposal.
    • Pro:
      • quite straightforward to implement, storage is quite clear.
      • Only one set of required rights which matches that also rights are the same for all translations.
    • Contra:
      • having an enabled status per translation is not intuitive at all, in particular if the required rights aren’t per translation and thus, e.g., adding a script macro to a translation requires adding the required right to the main document.
  2. Have required rights per translation by storing them inside the document and thus also inside translations.
    • Pro:
      • If just a single translation needs script right, script right can be required just for that translation.
      • The required rights analysis for cases like adding a script macro is much clearer and doesn’t, e.g., need to consider all translations.
      • Changing required rights also automatically updates the respective author of the affected document instance.
    • Contra:
      • There are cases like translations where an XObject on the main document affects all translations as in that case all translations need script or wiki admin right depending on the scope defined in the main document.
      • More complexity on the UI side as suddenly rights can be different per translations, a user might not be able to edit a document but might be able to translated it/edit a translation - though in this case if the requirement comes from the content itself, the actual translation won’t work.
      • We most likely don’t check rights with a document reference that includes the locale, so the right check might be wrong in many cases.
  3. Store both the enabled status and the required rights only in the main document.
    • Pro:
      • Matches the behavior of the current rights.
      • Easier to explain in the UI as we don’t need to have a UI for each translation and, e.g., translation documents can have the required right status as a whole.
    • Contra:
      • The analysis result would display results from all languages, and it is not clear to me if this should only be enabled languages or all languages.
      • Enabling required rights won’t automatically update the author of all translations and thus won’t automatically grant the desired rights.
      • I have no idea how to implement the storage, maybe it could be the same as option 1, but we ignore the enabled flag on translations and always display and set the flag on the main document?
      • Having, e.g., a JavaScript extension object on the main document means that also translations cannot be edited by users without script right.

I think I’m leaning towards solution option 3 as it avoids some complexity, but I would like to get some feedback on it first.

Apparently we have similar issues with the hidden flag that is stored and edited per translation but sometimes (?) only considered when it is on the main document. Another similar case is the creator right that is from all I know only granted to the creator of the main document, so somebody creating a translation cannot delete it again as rights currently don’t take translations into account.