{"id":1511,"date":"2021-08-27T21:01:33","date_gmt":"2021-08-27T19:01:33","guid":{"rendered":"https:\/\/hobbykeller.spdns.de\/?p=1511"},"modified":"2022-06-25T18:19:22","modified_gmt":"2022-06-25T16:19:22","slug":"restrict-users-to-particular-ressources-in-mayan-edms","status":"publish","type":"post","link":"https:\/\/hobbykeller.spdns.de\/?p=1511","title":{"rendered":"Restrict document access for users in Mayan EDMS"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">1. Situation \/ Problem<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>There are two (or more) organizational units.<\/li><li>Each org unit uses Mayan to manage its documents.<\/li><li>Each unit should only see and work on its own documents in Mayan. Any document resources from other org units should neither be visible nor alterable.<\/li><\/ul>\n\n\n\n<p>The easiest approach to achieve this goal would be to <strong>set up two separate Mayan instances<\/strong>. This could be achieved with two separate virtual Mayan environments on one machine (which could then at least share a single database server running two separate databases). Or separating things further, we could even set up two completely different (virtual, Docker containers or even physical) machines which each contain the whole suite of services (PostgreSQL server, Redis, Venv and all the other stuff) on a standalone basis.<\/p>\n\n\n\n<p>The main disadvantage of such an approach would be duplication. This is particularly inconvenient, when it comes to keeping all separate systems updated. Mayan releases an upgrade about each fortnight on average, and the <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.mayan-edms.com\/releases\/partials\/upgrade-3.5-4.0.html\" target=\"_blank\" class=\"broken_link\">process<\/a> is quite cumbersome. If you run a separate system for each org unit, this means having to go through the same tedious upgrade procedure each and every time. And the same might go for the operating systems of each virtual or physical machine.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. Sharing Mayan EDMS over multiple organizations<\/h2>\n\n\n\n<p>Mayan prides itself for its highly granular and customizable access control. Not only does it allow an unlimited number of <strong>users<\/strong>, but it can also define an unlimited amount of <strong>groups<\/strong> which users can be added to and <strong>roles<\/strong> which determine the <strong>privileges<\/strong> granted to each group. User groups can than be awarded one or more roles through which member users obtain these privileges indirectly.<\/p>\n\n\n\n<p>On top of that, each resource &#8211; be it a single document, a document type or even a cabinet comes with individual access control lists which can fine-tune the access privileges at the object level.<\/p>\n\n\n\n<p>With all these instruments, it should be possible to keep separate org units on the same Mayan installation from messing around with each other&#8217;s documents.<\/p>\n\n\n\n<p>The downside is that controlling access privileges with all these settings to toggle is not trivial at all. Worse still, the <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.mayan-edms.com\/parts\/access_control.html\" target=\"_blank\" class=\"broken_link\">documentation<\/a> is limited to rudimentary descriptions. Even the <a rel=\"noreferrer noopener\" href=\"https:\/\/www.mayan-edms.com\/book\/\" target=\"_blank\">book<\/a> only offers advice of the &#8220;in order to add a user to a group click the &#8216;Add user to group&#8217; button&#8221; style. It elaborates in great detail on things that you would have known anyway but offers few instructions on conceptual matters. No worked examples worth mentioning which would have helped with our problem.<\/p>\n\n\n\n<p>There were a couple of <a rel=\"noreferrer noopener\" href=\"https:\/\/forum.mayan-edms.com\/viewtopic.php?t=13\" target=\"_blank\" class=\"broken_link\">hints in the Mayan user foru<\/a>m, which helped a little and  a <a rel=\"noreferrer noopener\" href=\"https:\/\/interestingittips.wordpress.com\/2021\/05\/15\/v-users-groups-roles-acl\/\" target=\"_blank\">worked example on users, roles and ACLS<\/a> from a blog unrelated to the Mayan EDMS developers. After a lot of trial and error, here&#8217;s how to set up a single Mayan instance to deal with completely different org units&#8230;<\/p>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">3. The How To<\/h2>\n\n\n\n<p>Suppose we have two organziations: The Baltimore Buyout Group (BBG) and the High Frequency Trading Corp. (HFT). Both HFT and BBG want to use the single Mayan instance we are running, and we have to guarantee that each org can only see or alter the content they uploaded themselves and not the other one&#8217;s content. In other words, each group should have the impression that it is the only user of the system. The only persons which should have unlimited access to any document on the server are the users that have been connected to the admin role.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3.1 Add standard users<\/h3>\n\n\n\n<p><br>As the admin, the first thing to do is to set up standard users in Mayan. Broadly speaking, these users should be able to upload new documents to the server, perform searches on the documents that belong to their org unit and do basic editing like adding or removing tags, filing into cabinets (but only those belonging to the own organziation), maybe deleting documents (but not from the trash).<\/p>\n\n\n\n<p>We will add user <code>waldorf<\/code> who is a member of BBG and <code>statler<\/code> who is a member of HFT.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3.2 Define Groups<\/h3>\n\n\n\n<p>Using <code>Setup \/ Groups<\/code> as the admin, we create a group <code>g_BBG<\/code> and <code>g_HFT<\/code>. We then add <code>waldorf<\/code> to <code>g_BBG<\/code> and <code>statler<\/code> to <code>g_HFT<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3.3 Define Roles<\/h3>\n\n\n\n<p>In line with the groups we created, we create the roles. We start with creating <code>r_blank_bbg<\/code>. This is the role of the standard user from the group <code>g_bbg<\/code> inside the BBG organization.<\/p>\n\n\n\n<p>As the next step, we associate the group <code>g_BBG<\/code> with our role <code>r_blank_bbg<\/code>.<\/p>\n\n\n\n<p>Now comes the important part: We set the permissions for <code>r_blank_bbg<\/code>. Though it may counterintuitive, <strong>we do not grant any permission at all to this group<\/strong>. The reason is that role permissions have always a system-wide effect. If we add a permission <code>View Documents<\/code> to the role, this privilege is valid for <strong>any<\/strong> document on the system &#8211; exactly the thing we want to avoid. Users in group <code>g_bbg<\/code> should only be able to view documents of the BBG organization and not of HFT &#8211; they should not be able to view any document.<\/p>\n\n\n\n<p>After you are done, with <code>r_blank_bbg<\/code>, create another role <code>r_blank_hft<\/code> and repeat the same steps again, this time associating group <code>g_hft<\/code> and granting no permission at all to this role.<\/p>\n\n\n\n<div class=\"wp-block-simple-alerts-for-gutenberg-alert-boxes sab-alert sab-alert-primary\" role=\"alert\">Any <strong>role<\/strong> based authorization grants a permission for the <strong>whole<\/strong> system. Role permissions are therefore suitable for authorizing <strong>IT staff<\/strong> and <strong>administrators<\/strong> to do things like creating or deleting users; adding or deleting document types, tags etc; rebuilding search indices etc.<br>If you want to prevent <strong>end users<\/strong> from accessing certain documents or cabinets while giving access to certain other documents, you cannot do this by role permissions. The thing you have to go for is <strong>ACL<\/strong>s (access control lists).<button type=\"button\" class=\"close\" data-dismiss=\"alert\" aria-label=\"Close\"><span aria-hidden=\"true\">\u00d7<\/span><\/button><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">3.4 Add document types<\/h3>\n\n\n\n<p>Now we start actually separating privileges to access particular documents along organizational lines.<\/p>\n\n\n\n<p>As admin, we create a document type (<code>Setup<\/code> \/ <code>Document Types<\/code> \/ <code>Action<\/code> \/ <code>Create new document type<\/code>) <code>bbg_bank_statement<\/code>, which users from BBG should be allowed to use to process any of their bank statements in the system.<\/p>\n\n\n\n<div class=\"wp-block-simple-alerts-for-gutenberg-alert-boxes sab-alert sab-alert-primary\" role=\"alert\">As an administrator do yourself a favour and <strong>prefix<\/strong> any document type label by an organizational prefix. Use <em>bbg<\/em>_bank_statement instead of bank_statement. This will prevent you from confounding organizational ownership of document types lateron and grant some group access to documents they should not have access to.<button type=\"button\" class=\"close\" data-dismiss=\"alert\" aria-label=\"Close\"><span aria-hidden=\"true\">\u00d7<\/span><\/button><\/div>\n\n\n\n<p>Now comes the important part: For that document type, click on <code>ACL<\/code>, then click <code>New ACL<\/code> and select role <code>r_blank_bbg<\/code>. Then grant the following set of permissions to that role:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>Comments<\/strong><br>Create new comments<br>View comments<br><br><strong>Document checkout<\/strong><br>Check in documents<br>Check out details view<br>Check out documents<br>Forcefully check out documents<br><br><strong>Document parsing<\/strong><br>Parse the content of a document file<br>View the content of a document file<br><br><strong>Document types<\/strong><br>View document types<br><br><strong>Documents<\/strong><br>Create document versions<br>Create documents<br>Create new document files<br>Delete document files<br>Download document files<br>Edit document files<br>Edit document versions<br>Edit documents<br>Execute doc file modifying tools<br>Execute doc modifying tools<br>Print document files<br>Print document versions<br>Trash documents<br>View document files<br>View document versions<br>View documents<\/td><td><strong>Events<\/strong><br>Access events of an object<br><br><strong>File metadata<\/strong><br>Submit doc for metadata processing<br>View file metadata<br><br><strong>Metadata<\/strong><br>Add metadata to a document<br>Edit a document&#8217;s metadata<br>Remove metadata from a doc<br><br><strong>OCR<\/strong><br>Submit documents for OCR<br>View the transcribed text for a doc<br><br><strong>Tags<\/strong><br>Attach tags to documents<br>Remove tags from documents<br>View tags<\/td><\/tr><\/tbody><\/table><figcaption>Permissions to be added to document type ACL<\/figcaption><\/figure>\n\n\n\n<p>After adding the above permissions, you ACL should look somewhat like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2021\/08\/mayan_permissions.png\"><img loading=\"lazy\" decoding=\"async\" width=\"865\" height=\"596\" src=\"https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2021\/08\/mayan_permissions.png\" alt=\"\" class=\"wp-image-1513\" srcset=\"https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2021\/08\/mayan_permissions.png 865w, https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2021\/08\/mayan_permissions-300x207.png 300w, https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2021\/08\/mayan_permissions-768x529.png 768w\" sizes=\"auto, (max-width: 865px) 100vw, 865px\" \/><\/a><figcaption>ACL entries for document type<\/figcaption><\/figure>\n\n\n\n<p>You can now repeat the same steps for any other document that should be accessible for another group-role combination. For instance, you can create a document type <code>hft_contract<\/code> which holds all contract documents of the HFT organization.<\/p>\n\n\n\n<p>Again click on <code>ACL<\/code>, select role <code>r_blank_hft<\/code> and then assign the same set of privileges as above to <code>r_blank_hft<\/code> for document type <code>htf_contract<\/code>.<\/p>\n\n\n\n<p>Any new document type set up with the above types will inherit the role\/group specific acces privileges.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3.5 Set up cabinets<\/h3>\n\n\n\n<p>As a second means to separate document access privileges and organize documents along organizational lines, we can set up cabinets. Again, these cabs should only be visible and accessible to the org unit for which the cab was created.<\/p>\n\n\n\n<p>As the admin, click on <code>Cabinets<\/code> \/ <code>Create Cabinet<\/code> and create a main cabinet called BBG. This is the top-level cabinet under which every document associated to cabinets in the BBG org is filed.<\/p>\n\n\n\n<p> Then click on <code>ACLs<\/code>, select <code>r_blank_bbg<\/code> and add the grant the following permissions:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2021\/08\/mayan_cabinet_permissions-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"884\" height=\"613\" src=\"https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2021\/08\/mayan_cabinet_permissions-1.png\" alt=\"\" class=\"wp-image-1515\" srcset=\"https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2021\/08\/mayan_cabinet_permissions-1.png 884w, https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2021\/08\/mayan_cabinet_permissions-1-300x208.png 300w, https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2021\/08\/mayan_cabinet_permissions-1-768x533.png 768w\" sizes=\"auto, (max-width: 884px) 100vw, 884px\" \/><\/a><figcaption>Cabinet permissions granted to role <code>r_blank_bbg<\/code> for top-level cabinet BBG<\/figcaption><\/figure>\n\n\n\n<p>Proceed the same way creating a top level cabinet HFT, select role <code>r_blank_hft<\/code> and grant the same set of permissions as above.<\/p>\n\n\n\n<p>Admins (not the standard users) are authorized to add <strong>sub-cabinets<\/strong> to the root cabinets we just created. These sub cabinets will automatically inherit the role\/permissions features of the root cabinet they are created under.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3.6 Tags and Metadata<\/h3>\n\n\n\n<p>As with document types and (sub-)cabinets, tags must be created by the admin. Standard users are allowed to use these attach or remove these tags to documents, but cannot create, edit or delete new tags on their own.<\/p>\n\n\n\n<p>Once the admin has created a new tag, the tag&#8217;s ACL can then create a role\/permissions combination in the same way we did earlier with document types and cabinets:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2021\/08\/mayan_acl_tag.png\"><img loading=\"lazy\" decoding=\"async\" width=\"863\" height=\"602\" src=\"https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2021\/08\/mayan_acl_tag.png\" alt=\"\" class=\"wp-image-1525\" srcset=\"https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2021\/08\/mayan_acl_tag.png 863w, https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2021\/08\/mayan_acl_tag-300x209.png 300w, https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2021\/08\/mayan_acl_tag-768x536.png 768w\" sizes=\"auto, (max-width: 863px) 100vw, 863px\" \/><\/a><figcaption>ACL based authorization for role <code>r_blank_hft<\/code> to use a tag<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<!--nextpage-->\n\n\n\n<h2 class=\"wp-block-heading\">4. Testing<\/h2>\n\n\n\n<p>Log in as user <code>waldorf<\/code> and try to upload a document for BBG group. When choosing the document type, you should only be able to see document type BBG &#8211; not HFT. <\/p>\n\n\n\n<p>After having uploaded the document, check if you can see the document under <code>Documents<\/code> \/ <code>Recently created<\/code> and access its features.<\/p>\n\n\n\n<p>Then log out and log in as user <code>statler<\/code> and see if you can proceed the same way loading up a document for HFT. Again when picking the document type, you should only see HFT, not BBG (or Default). Check if you can see your document under <code>Documents<\/code> \/ <code>Recently created<\/code> &#8211; and make sure, the BBG document you uploaded recently as <code>waldorf<\/code> does not show up among the recently created docs.<\/p>\n\n\n\n<p>Pick the cabinets and make sure that only the HFT cabinet is visible, not BBG.<\/p>\n\n\n\n<p>Add some search term unique to the BBG document to the search box and make sure, the search does not return the BBG document you checked in as <code>waldorf<\/code>. You should get an empty search. Repeat the test with a search term unique to the HFT document you just checked in. The search should return the document to you.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5. Open issues<\/h2>\n\n\n\n<p>We still have the following issues to deal with:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5.1 Tags and metadata org specific or not?<\/h3>\n\n\n\n<p>Should user be allowed to create new tags (pro: the one who uploads a new document knows best what tags to associate with the doc, con: redundant tag names &#8211; once a user adds tag &#8216;capital gains tax&#8217;, the next time it&#8217;s &#8216;capital tax&#8217;)<\/p>\n\n\n\n<p>How handle metadata? We assume that metadata are always doc specific. So by forcing a particular set of doc types for a user group, we automatically force the metadata types. At least I would expect that &#8211; but we have to check.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5.2 Extension of a single org Mayan into a multi-org Mayan<\/h3>\n\n\n\n<p>Assume we have started with a single org Mayan which has thousands of docs checked in by the admin. How can we amend this instance of Mayan to the setup above? We want another organization to be able to also add its documents and separation of privileges along the lines we demonstrated in the previous sections.<\/p>\n\n\n\n<p>The draft to do list is probably like that:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Create a user for the current organization<\/li><li>Create a group for the current organization<\/li><li>Create a blank role for the current organization, associate role to the group just created<\/li><li>Create doc types for the current organization and set ACLs associated with the doc type and the blank role<\/li><li>Create cabinets and sub-cabinets for the current organization and set ACLs associated with the cabinet and the blank role<\/li><li>Use some bulk editing to alter the document types of all documents previously checked in under the &#8220;global&#8221; document types. This should be the tricky part.<\/li><\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">5.3 Extend direct SQL search to restrict results to a single organization<\/h3>\n\n\n\n<p>The very purpose of any document management system is its ability to quickly and reliably retrieve a particular set of documents from the thousands of documents which have been archived in the system.<\/p>\n\n\n\n<p>Unfortunately, Mayan&#8217;s search function is not only badly implemented but also features an incredibly lousy documentation. The only way I found to save Mayan from becoming useless due to its search function is to bypass it by directly querying the PostgreSQL data base.<\/p>\n\n\n\n<p>The SQL scripts currently allow to to retrieve the Mayan document IDs for a certain document given a search string to match and some metadata information. These scripts must be extended to restrict search results to a particular cabinet hierarchy or document type.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>1. Situation \/ Problem There are two (or more) organizational units. Each org unit uses Mayan to manage its documents. Each unit should only see and work on its own<span class=\"more-button\"><a href=\"https:\/\/hobbykeller.spdns.de\/?p=1511\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\">Restrict document access for users in Mayan EDMS<\/span><\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[329,328,289],"class_list":["post-1511","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-access-control","tag-acl","tag-mayan-edms"],"_links":{"self":[{"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=\/wp\/v2\/posts\/1511","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1511"}],"version-history":[{"count":10,"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=\/wp\/v2\/posts\/1511\/revisions"}],"predecessor-version":[{"id":1562,"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=\/wp\/v2\/posts\/1511\/revisions\/1562"}],"wp:attachment":[{"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1511"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1511"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1511"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}