def test_allow_view_if_user_has_perm(self):
        """
        Changing of the document should be restricted only to users who have
        PERM_WRITE permissions for respective document.
        """
        document_path = os.path.join(BASE_DIR, "data", "berlin.pdf")

        doc = Document.objects.create_document(
            user=self.testcase_user,
            title='berlin.pdf',
            size=os.path.getsize(document_path),
            lang='deu',
            file_name='berlin.pdf',
            page_count=3)

        document_url = reverse('core:document', args=(doc.id, ))

        create_access(
            node=doc,
            name=self.margaret_user.username,
            model_type=Access.MODEL_USER,
            access_type=Access.ALLOW,
            access_inherited=False,
            permissions={
                READ: True,
            }  # allow margaret to read/view the document
        )
        #
        # Margaret does not have access to document
        # berlin.pdf
        self.client.login(testcase_user=self.margaret_user)

        ret = self.client.get(document_url)
        self.assertEqual(ret.status_code, 200)
    def test_newly_created_subfolder_inherits_from_parent(self):
        """
        Newly created folder inherits access permissions from its
        parent folder.
        """
        new_folder = Folder.objects.create(title="creator_owns_me",
                                           user=self.uploader_user)
        # create custom read access for margaret
        create_access(
            node=new_folder,
            model_type=Access.MODEL_USER,
            name=self.margaret_user,
            access_type=Access.ALLOW,
            access_inherited=False,
            permissions={READ: True}  # allow read access to margaret
        )

        sub_folder = Folder.objects.create(title="subfolder for margaret",
                                           user=self.uploader_user,
                                           parent=new_folder)

        # and subfolder inherited access permissions from its parent
        self.assertTrue(self.uploader_user.has_perms(FULL_ACCESS, sub_folder))

        # margaret can read it (because parent folder is readable by parent)
        self.assertTrue(self.margaret_user.has_perm(READ, sub_folder))

        # but margaret cannot write to it, because so are
        # access permissions inherited from parent folder.
        self.assertFalse(self.margaret_user.has_perm(WRITE, sub_folder))
        self.assertFalse(self.margaret_user.has_perms(FULL_ACCESS, sub_folder))
    def test_no_colateral_effect_on_siblings(self):
        """
        User margaret creates two folders:

            * margaret_privat  (f1)
            * from-margaret-to-elizabet (f2)

        Margaret decides to grant read access to elizabet on folder (f2).
        Expected:
            * elizabet has read access to (f2)
            * elizabet does *NOT* have read access to (f1)
        """
        # (f1)
        margaret_privat = Folder.objects.create(title="margaret_privat",
                                                user=self.margaret_user)
        # (f2)
        for_elizabet = Folder.objects.create(
            title="from-margaret-to-elizabet",
            user=self.margaret_user,
        )
        create_access(
            node=for_elizabet,
            model_type=Access.MODEL_USER,
            name=self.elizabet_user,
            access_type=Access.ALLOW,
            access_inherited=False,
            permissions={READ: True}  # allow read access to elizabet
        )
        self.assertTrue(self.elizabet_user.has_perm(READ, for_elizabet))
        self.assertFalse(self.elizabet_user.has_perm(READ, margaret_privat))
Exemple #4
0
    def test_tricky_scenario_1(self):
        """
            There are 4 users:
                * root (i.e. admin)
                * margaret
                * elizabet
                * uploader

            margaret and elizabeth are part of group Accountants.
            Admin user creates a folder titles 'for-Accountants'.
            Then, he (admin user) assigns access only with READ permision
            for Accountants group.

            Expected:
                * margaret and elizabet have read access on folder
                    'for-Accountants'
                * upload does not have read access on folder for-Accountants
        """
        for_accountants = Folder.objects.create(
            title="for-accountants",
            user=self.root_user
        )

        accountants = Group.objects.create(
            name="Accountants"
        )

        accountants.user_set.add(self.margaret_user)
        accountants.user_set.add(self.elizabet_user)

        create_access(
            node=for_accountants,
            model_type=Access.MODEL_GROUP,
            name="Accountants",
            access_type=Access.ALLOW,
            access_inherited=False,
            permissions={
                READ: True
            }  # allow read access to margaret
        )

        # permission via Accountants Group
        self.assertTrue(
            self.elizabet_user.has_perm(READ, for_accountants),
            "Elizabet must have access to for-accountants folder."
            " She is part of accountants group!"
        )
        # permission via Accountants Group
        self.assertTrue(
            self.margaret_user.has_perm(READ, for_accountants),
            "Margaret must have access to for-accountants folder."
            " She is part of accountants group!"
        )
        # uploader is not part of accountants group
        self.assertFalse(
            self.uploader_user.has_perm(READ, for_accountants),
            "Uploader must NOT have access to for-accountants folder."
            " He is NOT part of accountants group!"
        )
Exemple #5
0
    def test_read_access_only(self):
        """
        User can access documents and folders only for which he/she
        has read access
        """
        Folder.objects.create(
            title="Root's Folder",
            user=self.root_user,
        )
        shared1 = Folder.objects.create(
            title="Shared 1",
            user=self.root_user,
        )
        shared2 = Folder.objects.create(
            title="Shared 2",
            user=self.root_user,
        )
        Folder.objects.create(
            title="Margaret's Folder",
            user=self.margaret_user,
        )
        create_access(
            node=shared1,
            model_type=Access.MODEL_USER,
            name=self.margaret_user,
            access_type=Access.ALLOW,
            access_inherited=False,
            permissions={Access.PERM_READ:
                         True}  # allow read access to elizabet
        )
        create_access(
            node=shared2,
            model_type=Access.MODEL_USER,
            name=self.margaret_user,
            access_type=Access.ALLOW,
            access_inherited=False,
            permissions={Access.PERM_READ:
                         True}  # allow read access to elizabet
        )
        self.client.login(testcase_user=self.margaret_user)
        # margaret will see 3 folders:
        # shared1 (which root user shared with her)
        # shared2 (which root shared with her)
        # and her own.
        json_response, status_code = self._browse_nodes()

        self.assertEqual(status_code, 200)
        # will return children Child1, Child2, Child3
        self.assertEqual(len(json_response['nodes']), 3)
        returned_node_titles_set = set(
            [node['title'] for node in json_response['nodes']])
        self.assertEqual(returned_node_titles_set,
                         set(['Shared 1', 'Shared 2', "Margaret's Folder"]))
Exemple #6
0
def node_post_save(sender, node, created, *kwargs):
    if created:
        # New node instance was created.
        # Create associated Access Model:
        # node creater has full access.
        create_access(
            node=node,
            model_type=Access.MODEL_USER,
            name=node.user.username,
            access_type=Access.ALLOW,
            access_inherited=False,
            permissions=Access.OWNER_PERMS_MAP  # full access
        )

    # Consider this two persons use case:
    # User uploader uploads scans for user margaret.
    # Initially document is in uploader's Inbox folder.
    # Afterwards, uploader moves new document X into common shared_folder.
    # shared_folder has full access permissions for
    # boths uploader and margaret.
    # When margaret sees document X, she copies it into
    # her private folder X_margaret_fld. X_margaret_fld is
    # owned only by margaret.
    # Now document X's path is margaret//X_margaret_fld/X.pdf
    # If X.pdf access permissions stay same, then uploader will
    # still have access to X.pdf (via search) which means,
    # that margaret will need to change manually X.pdf's
    # access permissions. To avoid manual change of access
    # permissions from margaret side - papermerge feature
    # is that X.pdf inherits access permissions from new
    # parent (X_margaret_fld). Thus, just by copying it,
    # X.pdf becomes margaret private doc - and uploader
    # lose its access to it.
    if node.parent:  # current node has a parent?
        # Following statement covers case when node
        # is moved from one parent to another parent.

        # When node moved from one parent to another
        # it get all its access replaced by access list of the
        # parent
        access_diff = AccessDiff(
            operation=AccessDiff.REPLACE,
            access_set=node.parent.access_set.all()
        )
        node.propagate_access_changes(
            access_diffs=[access_diff],
            apply_to_self=True
        )
    else:
        # In case node has no parent, all its access permission
        # remain the same.
        pass
    def test_allow_delete_if_user_has_perm(self):
        """
        Deleting Document should be restricted only to users who have
        PERM_DELETE permissions
        """
        document_path = os.path.join(BASE_DIR, "data", "berlin.pdf")

        doc = Document.objects.create_document(
            user=self.testcase_user,
            title='berlin.pdf',
            size=os.path.getsize(document_path),
            lang='deu',
            file_name='berlin.pdf',
            page_count=3)
        self.assertEqual(Document.objects.count(), 1)

        nodes_url = reverse('core:document', args=(doc.id, ))

        nodes_data = [
            {
                'id': doc.id
            },
        ]
        create_access(
            node=doc,
            name=self.margaret_user.username,
            model_type=Access.MODEL_USER,
            access_type=Access.ALLOW,
            access_inherited=False,
            permissions={
                READ: True,
                DELETE: True
            }  # allow margaret to delete
        )
        #
        # Margaret was assigned access to delete the document
        # berlin.pdf
        self.client.login(testcase_user=self.margaret_user)

        ret = self.client.delete(
            nodes_url,
            json.dumps(nodes_data),
            content_type='application/json',
            HTTP_X_REQUESTED_WITH='XMLHttpRequest',
        )
        self.assertEqual(ret.status_code, 200)
        # because margaret does not have access to the
        # document -> it should be still there
        self.assertEqual(Document.objects.count(), 0)
    def test_allow_change_if_user_has_perm(self):
        """
        Changing of the document should be restricted only to users who have
        PERM_WRITE permissions for respective document.
        """
        document_path = os.path.join(BASE_DIR, "data", "berlin.pdf")

        doc = Document.objects.create_document(
            user=self.testcase_user,
            title='berlin.pdf',
            size=os.path.getsize(document_path),
            lang='deu',
            notes="Margaret, you are allowed to change this.",
            file_name='berlin.pdf',
            page_count=3)
        self.assertEqual(Document.objects.count(), 1)

        document_url = reverse('core:document', args=(doc.id, ))

        document_data = {'notes': "It works!"}

        create_access(
            node=doc,
            name=self.margaret_user.username,
            model_type=Access.MODEL_USER,
            access_type=Access.ALLOW,
            access_inherited=False,
            permissions={
                READ: True,
                WRITE: True
            }  # allow margaret to delete
        )

        #
        # Margaret does not have access to document
        # berlin.pdf
        self.client.login(testcase_user=self.margaret_user)

        ret = self.client.patch(
            document_url,
            json.dumps(document_data),
            content_type='application/json',
            HTTP_X_REQUESTED_WITH='XMLHttpRequest',
        )
        self.assertEqual(ret.status_code, 200)
        # because margaret does not have access to the
        doc.refresh_from_db()
        self.assertEqual(doc.notes, "It works!")
Exemple #9
0
    def test_create_access_from_another_user_based_access(self):
        """
        Given an access a1 associated to a user margaret.
        New access a2 is created from a1.
        Expected: access a2 will have associated user margaret as well.
        """
        new_folder = Folder.objects.create(
            title="creator_owns_me",
            user=self.uploader_user
        )

        a1 = create_access(
            node=new_folder,
            model_type=Access.MODEL_USER,
            name="margaret",
            access_type=Access.ALLOW,
            access_inherited=False,
            permissions={
                READ: True
            }  # allow read access to margaret
        )

        a2 = Access.create(
            node=new_folder,
            access_inherited=True,
            access=a1
        )
        self.assertEqual(
            a2.user.username,
            "margaret"
        )
    def test_set_access_perms_returns_correct_diffs_2(self):
        """
        1. New folder is created by uploader
        2. New folder has margaret READ & WRITE & DELETE access (allow)
        3. User tries to leave for margaret only read permission.
         (it will set_access_perms only with READ flag)
        """
        node = Folder.objects.create(title="some_folder",
                                     user=self.uploader_user)

        create_access(node=node,
                      model_type=Access.MODEL_USER,
                      name=self.margaret_user,
                      access_type=Access.ALLOW,
                      access_inherited=False,
                      permissions={
                          READ: True,
                          WRITE: True,
                          DELETE: True
                      })
        access_diffs = set_access_perms(
            node,
            [{
                'model': 'user',
                'name': 'margaret',
                'access_type': 'allow',
                'permissions': {
                    'read': True,  # only read flag
                }
            }])
        # only one entry AccessDiff(operation=ADD)
        self.assertEqual(len(access_diffs), 1,
                         [str(diff) for diff in access_diffs])

        self.assertEqual(access_diffs[0].operation, AccessDiff.UPDATE)

        access = access_diffs[0].pop()
        self.assertEqual("margaret", access.user.username)
        self.assertEqual("allow", access.access_type)
        perms = set()
        perms.add("read")

        self.assertEqual(perms, access.perms_codenames())
    def test_changes_resursive_inheritance(self):
        """
        1. uploader creates:
            F1 -> L1a -> L2a -> L3a
            F1 -> L1b -> L2b

        2. Uploader gives read access to margaret on F1

        3. Margaret will have read access on L1a, L1b, L2a, L2b,
            L3a as well (because of recursive inheritance)
        """
        F1 = Folder.objects.create(title="F1", user=self.uploader_user)
        L1a = Folder.objects.create(title="L1a",
                                    user=self.uploader_user,
                                    parent=F1)
        L2a = Folder.objects.create(title="L2a",
                                    user=self.uploader_user,
                                    parent=L1a)
        L3a = Folder.objects.create(title="L3a",
                                    user=self.uploader_user,
                                    parent=L2a)
        L1b = Folder.objects.create(title="L1b",
                                    user=self.uploader_user,
                                    parent=F1)
        L2b = Folder.objects.create(title="L2b",
                                    user=self.uploader_user,
                                    parent=L1b)
        # give margaret read access on topmost folder
        new_access = create_access(
            node=F1,
            model_type=Access.MODEL_USER,
            name=self.margaret_user,
            access_type=Access.ALLOW,
            access_inherited=False,
            permissions={READ: True}  # allow read access to margaret
        )
        # function which does the trick
        access_diff = AccessDiff(operation=AccessDiff.ADD,
                                 access_set=[new_access])
        F1.propagate_access_changes(access_diffs=[access_diff],
                                    apply_to_self=True)

        # and assert
        for folder in [F1, L1a, L1b, L2a, L3a, L2b]:
            self.assertTrue(self.margaret_user.has_perm(READ, folder),
                            f"margaret: Failed for folder {folder.title}")
            # uploader still has full access ?
            self.assertTrue(self.uploader_user.has_perms(FULL_ACCESS, folder),
                            f"uploader: Failed for folder {folder.title}")
    def test_user_download_document(self):
        """
        If user has read access to the document
        (even if he/she is not the owner of the document), then
        he/she must be able to download it.

        Scenario:
            admin user creates a document and assigns
            read only access for margaret
            (thus, root is the owner of the document).

        Expected:

            Margaret and root user must be able to download the document.
            Elizabet on the other hand - must not have access to the document
            (she was not assigned permissions for that)
        """
        document_path = os.path.join(
            BASE_DIR, "data", "berlin.pdf"
        )

        doc = Document.create_document(
            user=self.root_user,
            title='berlin.pdf',
            size=os.path.getsize(document_path),
            lang='deu',
            file_name='berlin.pdf',
            page_count=3
        )
        # copy document from its test/data place
        # to the media storage, as if document was uploaded.
        default_storage.copy_doc(
            src=document_path,
            dst=doc.path.url(),
        )
        create_access(
            node=doc,
            name=self.margaret_user.username,
            model_type=Access.MODEL_USER,
            access_type=Access.ALLOW,
            access_inherited=False,
            permissions={
                READ: True
            }  # allow read access to margaret
        )
        self.client.login(
            testcase_user=self.margaret_user
        )

        url = reverse(
            'core:document_download', args=(doc.id,)
        )

        ret = self.client.get(url)

        self.assertEqual(
            ret.status_code,
            200
        )

        # also, root/admin must be able to download it
        self.client.logout()
        self.client.login(
            testcase_user=self.root_user
        )

        ret = self.client.get(url)

        self.assertEqual(
            ret.status_code,
            200
        )

        self.client.logout()

        # for elizabet on the other hand, access is forbidden.
        self.client.login(testcase_user=self.elizabet_user)
        ret = self.client.get(url)

        self.assertEqual(
            ret.status_code,
            403
        )
Exemple #13
0
    def test_move_files_from_uploader_to_margaret(self):
        """
        Uploader creates following folder struture:

        1.
            * upload/for_margaret/mx1
            * upload/for_margaret/mx2

        2.
        uploader Creates root level folder shared_documents
        and assigns it full access to margaret:

            * upload/for_margaret/mx1
            * upload/for_margaret/mx2
            * shared_folder  <- both uploader and margaret have full access

        3. uploader moves folder for_margaret into shared_folder:

            * upload
            * shared_folder/for_margaret/mx1
            * shared_folder/for_margaret/mx1

        4. Margaret can now see and access all for_margaret, mx1 and mx2:

            * shared_folder/for_margaret/mx1
            * shared_folder/for_margaret/mx1

        5. Margaret creates private folder margaret_private

        6. Margaret moves shared_folder/for_margaret into margaret_private:

            * shared_folder
            * margaret_private/for_margaret/mx1
            * margaret_private/for_margaret/mx2

        7. Now ONLY margaret can see and access
            * margaret_private/for_margaret/
            * margaret_private/for_margaret/mx1
            * margaret_private/for_margaret/mx2

        Why?
        Because moved folders for_margaret, mx1, mx2 inherited
        their new access rights from their new parent while
        old access rights were deleted.
        """
        # 1
        upload = Folder.objects.create(
            title="upload",
            user=self.uploader_user
        )
        for_margaret = Folder.objects.create(
            title="for_margaret",
            user=self.uploader_user,
            parent=upload
        )
        mx1 = Folder.objects.create(
            title="mx1",
            user=self.uploader_user,
            parent=for_margaret
        )
        mx2 = Folder.objects.create(
            title="mx2",
            user=self.uploader_user,
            parent=for_margaret
        )
        # 2
        shared_folder = Folder.objects.create(
            title="shared_folder",
            user=self.uploader_user
        )
        create_access(
            node=shared_folder,
            model_type=Access.MODEL_USER,
            name=self.margaret_user,
            access_inherited=False,
            access_type=Access.ALLOW,
            permissions={
                Access.PERM_READ: True,
                Access.PERM_WRITE: True,
                Access.PERM_DELETE: True,
                Access.PERM_TAKE_OWNERSHIP: True,
                Access.PERM_CHANGE_PERM: True
            }
        )

        self.assertTrue(
            self.margaret_user.has_perms(FULL_ACCESS, shared_folder)
        )
        self.assertTrue(
            self.uploader_user.has_perms(FULL_ACCESS, shared_folder)
        )

        # as of yet, margaret does not has access to mx1, mx2, for_margaret
        for folder in [mx1, mx2, for_margaret]:
            self.assertFalse(
                self.margaret_user.has_perms(FULL_ACCESS, folder),
                f"Failed for folder {folder.title}"
            )

        # 3 - uploader moves folder for_margaret into shared_folder

        Folder.objects.move_node(for_margaret, shared_folder)
        # 4 - margaret now has full access to for_margaret, mx1, mx2
        for folder in [mx1, mx2, for_margaret]:
            # both, margaret and upload have full access
            self.assertTrue(
                self.margaret_user.has_perms(FULL_ACCESS, folder),
                f"Failed for folder {folder.title}"
            )
            self.assertTrue(
                self.uploader_user.has_perms(FULL_ACCESS, folder),
                f"Uploader has access to {folder.title}. Wrong code!"
            )

        # 5. Margaret creates private folder margaret_private
        private_folder = Folder.objects.create(
            title="private",
            user=self.margaret_user
        )

        # 6. Margaret moves shared_folder/for_margaret into margaret_private:
        Folder.objects.move_node(
            for_margaret,   # node to move
            private_folder  # new parent
        )

        # 7
        for folder in [mx1, mx2, for_margaret]:
            self.assertTrue(
                self.margaret_user.has_perms(FULL_ACCESS, folder),
                f"Failed for folder {folder.title}"
            )
            # uploader lost its access permissions for mx1, mx2,
            # for_margaret folders
            self.assertFalse(
                self.uploader_user.has_perms(FULL_ACCESS, folder),
                f"Failed for folder {folder.title}"
            )