def test_delete_single_acl_and_count(self):

        session = self.acl_repo.get_session()
        container = self._create_base_container()
        acl1 = self.acl_repo.create_from(
            models.ContainerACL(container.id, 'read'), session)
        self.acl_repo.create_or_replace_from(container,
                                             acl1,
                                             user_ids=['u1', 'u2'])
        acl2 = self.acl_repo.create_from(
            models.ContainerACL(container.id, 'write'), session)
        self.acl_repo.create_or_replace_from(container,
                                             acl2,
                                             user_ids=['u1', 'u2', 'u3'])
        acl3 = self.acl_repo.create_from(
            models.ContainerACL(container.id, 'list'), session)
        self.acl_repo.create_or_replace_from(container,
                                             acl3,
                                             user_ids=['u1', 'u3'])

        count = self.acl_repo.get_count(container.id)
        self.assertEqual(3, count)

        self.acl_repo.delete_entity_by_id(acl2.id, None)
        session.commit()  # commit the changes made so far
        self.assertEqual(2, len(container.container_acls))

        deleted_acl = self.acl_repo.get(acl2.id, suppress_exception=True)
        self.assertIsNone(deleted_acl)

        acls = self.acl_repo.get_by_container_id(container.id)
        self.assertEqual(2, len(acls))

        count = self.acl_repo.get_count(container.id)
        self.assertEqual(2, count)
    def test_create_or_replace_from_for_new_acls(self):
        """Check create_or_replace_from and get count call.

        It creates new acls with users and make sure that same users
        are returned when acls are queries by secret id.
        It uses get count to assert expected number of acls for that secret.
        """
        session = self.acl_repo.get_session()
        container = self._create_base_container()
        acl1 = self.acl_repo.create_from(
            models.ContainerACL(container.id, 'read'), session)
        self.acl_repo.create_or_replace_from(container,
                                             acl1,
                                             user_ids=['u1', 'u2'],
                                             session=session)

        acl2 = self.acl_repo.create_from(
            models.ContainerACL(container.id, 'write', False), session)
        self.acl_repo.create_or_replace_from(container,
                                             acl2,
                                             user_ids=['u1', 'u2', 'u3'],
                                             session=session)

        acl3 = self.acl_repo.create_from(
            models.ContainerACL(container.id, 'list'), session)
        self.acl_repo.create_or_replace_from(container,
                                             acl3,
                                             user_ids=[],
                                             session=session)

        acls = self.acl_repo.get_by_container_id(container.id, session)

        self.assertEqual(3, len(acls))

        id_map = self._map_id_to_acl(acls)
        self.assertTrue(id_map[acl1.id].project_access)
        self.assertFalse(id_map[acl2.id].project_access)
        self.assertEqual('read', id_map[acl1.id].operation)
        self.assertEqual('write', id_map[acl2.id].operation)
        self.assertEqual('list', id_map[acl3.id].operation)
        # order of input users should not matter
        self._assert_acl_users(['u1', 'u2'], acls, acl1.id)
        self._assert_acl_users(['u2', 'u1'], acls, acl1.id)
        self._assert_acl_users(['u2', 'u1', 'u3'], acls, acl2.id)

        count = self.acl_repo.get_count(container.id, session)
        self.assertEqual(3, count)
        self.assertEqual(count, len(acls))
Beispiel #3
0
    def setUp(self):
        super(WhenTestingContainerResource, self).setUp()

        self.external_project_id = '12345project'
        self.container_id = '12345secret'
        self.user_id = '123456user'
        self.creator_user_id = '123456CreatorUser'

        # Force an error on GET and DELETE calls that pass RBAC,
        #   as we are not testing such flows in this test module.
        self.container_repo = mock.MagicMock()
        fail_method = mock.MagicMock(return_value=None,
                                     side_effect=self._generate_get_error())
        self.container_repo.get = fail_method
        self.container_repo.delete_entity_by_id = fail_method

        acl_read = models.ContainerACL(container_id=self.container_id,
                                       operation='read',
                                       project_access=True,
                                       user_ids=[self.user_id, 'anyRandomId'])
        self.acl_list = [acl_read]
        container = mock.MagicMock()
        container.to_dict_fields = mock.MagicMock(side_effect=IOError)
        container.id = self.container_id
        container.container_acls.__iter__.return_value = self.acl_list
        container.project.external_id = self.external_project_id
        container.creator_id = self.creator_user_id

        self.container_repo.get_container_by_id.return_value = container

        self.setup_container_repository_mock(self.container_repo)

        self.resource = ContainerResource(container)
 def test_new_containeracl_for_bare_minimum_input(self):
     acl = models.ContainerACL(self.container_id, self.operation, None,
                               None)
     self.assertEqual(self.container_id, acl.container_id)
     self.assertEqual(0, len(acl.acl_users))
     self.assertEqual(self.operation, acl.operation)
     self.assertIsNone(acl.project_access)
 def test_new_containeracl_for_given_all_input(self):
     acl = models.ContainerACL(self.container_id, self.operation,
                               self.project_access, self.user_ids)
     self.assertEqual(self.container_id, acl.container_id)
     self.assertEqual(self.operation, acl.operation)
     self.assertEqual(self.project_access, acl.project_access)
     self.assertTrue(
         all(acl_user.user_id in self.user_ids
             for acl_user in acl.acl_users))
    def test_delete_acls_for_secret(self):
        session = self.acl_repo.get_session()
        container = self._create_base_container()
        acl1 = self.acl_repo.create_from(
            models.ContainerACL(container.id, 'read'), session)
        self.acl_repo.create_or_replace_from(container,
                                             acl1,
                                             user_ids=['u1', 'u2'],
                                             session=session)
        acl2 = self.acl_repo.create_from(
            models.ContainerACL(container.id, 'write'), session)
        self.acl_repo.create_or_replace_from(container,
                                             acl2,
                                             user_ids=['u1', 'u2', 'u3'],
                                             session=session)

        self.acl_repo.delete_acls_for_container(container)
        acls = self.acl_repo.get_by_container_id(container.id)
        self.assertEqual(0, len(acls))
 def test_new_containeracl_with_duplicate_userids_input(self):
     user_ids = list(self.user_ids)
     user_ids *= 2  # duplicate ids
     acl = models.ContainerACL(self.container_id,
                               self.operation,
                               True,
                               user_ids=user_ids)
     self.assertEqual(self.container_id, acl.container_id)
     self.assertEqual(self.operation, acl.operation)
     self.assertTrue(acl.project_access)
     self.assertEqual(2, len(acl.acl_users))
    def test_get_count(self):
        session = self.acl_repo.get_session()
        container1 = self._create_base_container()
        acl1 = self.acl_repo.create_from(
            models.ContainerACL(container1.id, 'read', None, ['u1', 'u2']),
            session)
        self.acl_repo.create_or_replace_from(container1, acl1)

        container2 = self._create_base_container(container1.project_id)
        acl21 = self.acl_repo.create_from(
            models.ContainerACL(container2.id, 'read', None, ['u3', 'u4']),
            session)
        self.acl_repo.create_or_replace_from(container2, acl21)
        acl22 = self.acl_repo.create_from(
            models.ContainerACL(container2.id, 'write', None, ['u5', 'u6']),
            session)
        self.acl_repo.create_or_replace_from(container2, acl22)

        self.assertEqual(1, self.acl_repo.get_count(container1.id))
        self.assertEqual(2, self.acl_repo.get_count(container2.id))
    def test_create_or_replace_from_with_none_or_blank_users(self):
        session = self.acl_repo.get_session()
        container = self._create_base_container()
        acl1 = self.acl_repo.create_from(
            models.ContainerACL(container.id, 'read'), session)
        self.acl_repo.create_or_replace_from(container,
                                             acl1,
                                             user_ids=None,
                                             session=session)

        acl2 = self.acl_repo.create_from(
            models.ContainerACL(container.id, 'write'), session)
        self.acl_repo.create_or_replace_from(container,
                                             acl1,
                                             user_ids=[],
                                             session=session)

        acls = self.acl_repo.get_by_container_id(container.id, session)
        id_map = self._map_id_to_acl(acls)
        self.assertIsNone(id_map[acl1.id].to_dict_fields().get('users'))
        self.assertIsNone(id_map[acl2.id].to_dict_fields().get('users'))
 def test_new_containeracl_check_to_dict_fields(self):
     acl = models.ContainerACL(self.container_id, self.operation,
                               self.project_access, self.user_ids)
     self.assertEqual(self.container_id,
                      acl.to_dict_fields()['container_id'])
     self.assertEqual(self.operation, acl.to_dict_fields()['operation'])
     self.assertEqual(self.project_access,
                      acl.to_dict_fields()['project_access'])
     self.assertTrue(
         all(user_id in self.user_ids
             for user_id in acl.to_dict_fields()['users']))
     self.assertIsNone(acl.to_dict_fields()['acl_id'])
Beispiel #11
0
    def on_patch(self, external_project_id, **kwargs):
        """Handles update of existing container acl requests.

        At least one container ACL needs to exist for update to proceed.
        In update, multiple operation ACL payload can be specified as
        mentioned in sample below. A specific ACL can be updated by its
        own id via ContainerACLController patch request.

        {
          "read":{
            "users":[
              "5ecb18f341894e94baca9e8c7b6a824a",
              "20b63d71f90848cf827ee48074f213b7",
              "c7753f8da8dc4fbea75730ab0b6e0ef4"
            ]
          },
          "write":{
            "users":[
              "5ecb18f341894e94baca9e8c7b6a824a"
            ],
            "project-access":false
          }
        }
        """
        data = api.load_body(pecan.request, validator=self.validator)
        LOG.debug('Start ContainerACLsController on_patch...%s', data)

        existing_acls_map = {
            acl.operation: acl
            for acl in self.container.container_acls
        }
        for operation in itertools.ifilter(lambda x: data.get(x),
                                           validators.ACL_OPERATIONS):
            project_access = data[operation].get('project-access')
            user_ids = data[operation].get('users')
            if operation in existing_acls_map:  # update if matching acl exists
                c_acl = existing_acls_map[operation]
                if project_access is not None:
                    c_acl.project_access = project_access
            else:
                c_acl = models.ContainerACL(self.container.id,
                                            operation=operation,
                                            project_access=project_access)
            self.acl_repo.create_or_replace_from(self.container,
                                                 container_acl=c_acl,
                                                 user_ids=user_ids)

        acl_ref = '{0}/acl'.format(
            hrefs.convert_container_to_href(self.container.id))
        return {'acl_ref': acl_ref}
    def test_get_by_container_id(self):
        session = self.acl_repo.get_session()
        container = self._create_base_container()

        acls = self.acl_repo.get_by_container_id(container.id, session)
        self.assertEqual(0, len(acls))

        acl1 = self.acl_repo.create_from(
            models.ContainerACL(container.id, 'read', True, ['u1', 'u2']),
            session)
        acls = self.acl_repo.get_by_container_id(container.id, session)
        self.assertEqual(1, len(acls))
        self.assertEqual(acl1.id, acls[0].id)
        self.assertEqual('read', acls[0].operation)
        self._assert_acl_users(['u1', 'u2'], acls, acl1.id)
Beispiel #13
0
    def test_pass_get_container_for_admin_user_project_access_disabled(self):
        """Should pass authz for admin user when container is marked private.

        For private container, admin user should still be able to access
        the secret.
        """
        self.acl_list.pop()  # remove read acl from default setup
        acl_read = models.ContainerACL(container_id=self.container_id,
                                       operation='read',
                                       project_access=False,
                                       user_ids=['anyRandomUserX', 'aclUser1'])
        self.acl_list.append(acl_read)
        self._assert_pass_rbac(['admin'],
                               self._invoke_on_get,
                               user_id=self.user_id,
                               project_id=self.external_project_id)
Beispiel #14
0
    def test_pass_get_container_for_creator_user_project_access_disabled(self):
        """Should pass authz for creator user when container is marked private.

        As container is private so user who created the container can still
        access it as long as user has 'creator' role in container project.
        """
        self.acl_list.pop()  # remove read acl from default setup
        acl_read = models.ContainerACL(container_id=self.container_id,
                                       operation='read',
                                       project_access=False,
                                       user_ids=['anyRandomUserX', 'aclUser1'])
        self.acl_list.append(acl_read)
        self._assert_pass_rbac(['creator'],
                               self._invoke_on_get,
                               user_id=self.creator_user_id,
                               project_id=self.external_project_id)
Beispiel #15
0
    def test_should_raise_get_container_for_with_project_access_disabled(self):
        """Should raise authz error as container is marked private.

        As container is private so project users should not be able to access
        the secret (other than admin user).
        """
        self.acl_list.pop()  # remove read acl from default setup
        acl_read = models.ContainerACL(container_id=self.container_id,
                                       operation='read',
                                       project_access=False,
                                       user_ids=['anyRandomUserX', 'aclUser1'])
        self.acl_list.append(acl_read)
        self._assert_fail_rbac(['observer', 'creator', 'audit'],
                               self._invoke_on_get,
                               user_id=self.user_id,
                               project_id=self.external_project_id)
Beispiel #16
0
    def test_fail_get_container_for_creator_user_different_project(self):
        """Check for creator user rule for container get call.

        If token's user is creator of container but its scoped to different
        project, then he/she is not allowed access to container when project
        is marked private.
        """
        self.acl_list.pop()  # remove read acl from default setup
        acl_read = models.ContainerACL(container_id=self.container_id,
                                       operation='read',
                                       project_access=False,
                                       user_ids=['anyRandomUserX', 'aclUser1'])
        self.acl_list.append(acl_read)
        self._assert_fail_rbac(['creator'],
                               self._invoke_on_get,
                               user_id=self.creator_user_id,
                               project_id='differet_project_id')
Beispiel #17
0
    def test_should_pass_get_container_for_private_enabled_with_read_acl(self):
        """Should pass authz as user has read acl for private container.

        Even though container is private, user with read acl should be able to
        access the container.
        """
        self.acl_list.pop()  # remove read acl from default setup
        acl_read = models.ContainerACL(container_id=self.container_id,
                                       operation='read',
                                       project_access=False,
                                       user_ids=['anyRandomUserX', 'aclUser1'])
        self.acl_list.append(acl_read)
        self._assert_pass_rbac(
            ['admin', 'observer', 'creator', 'audit', 'bogusRole'],
            self._invoke_on_get,
            user_id='aclUser1',
            project_id=self.external_project_id)
    def test_get_by_entity_id(self):
        session = self.acl_repo.get_session()
        container = self._create_base_container()

        acl1 = self.acl_repo.create_from(
            models.ContainerACL(container.id, 'read', True, ['u1', 'u2']),
            session)

        acl = self.acl_repo.get(acl1.id, session)
        self.assertIsNotNone(acl)
        self.assertEqual(acl1.id, acl.id)
        self.assertEqual('read', acl.operation)
        self._assert_acl_users(['u1', 'u2'], [acl], acl1.id)

        self.acl_repo.delete_entity_by_id(acl1.id, session)
        acl = self.acl_repo.get(acl1.id, session, suppress_exception=True)
        self.assertIsNone(acl)
Beispiel #19
0
    def test_should_raise_get_container_for_different_user_with_no_read_acl(
            self):
        """Get secret fails when no read acl is defined.

        With different container and token's project, read is not allowed
        without a read ACL.
        """
        self.acl_list.pop()  # remove read acl from default setup
        acl_read = models.ContainerACL(container_id=self.container_id,
                                       operation='write',
                                       project_access=True,
                                       user_ids=['anyRandomUserX', 'aclUser1'])
        self.acl_list.append(acl_read)
        # token project_id is different from secret's project id but another
        # user (from different project) has read acl for secret so should pass
        self._assert_fail_rbac(['admin', 'observer', 'creator', 'audit'],
                               self._invoke_on_get,
                               user_id='aclUser1',
                               project_id='different_project_id')
Beispiel #20
0
    def test_should_pass_get_container_different_user_with_valid_read_acl(
            self):
        """Should allow when read ACL is defined for a user.

        Container's own project and token's project is different but read is
        allowed because of valid read ACL. User can read regardless of what is
        token's project as it has necessary ACL.
        """
        self.acl_list.pop()  # remove read acl from default setup
        acl_read = models.ContainerACL(container_id=self.container_id,
                                       operation='read',
                                       project_access=True,
                                       user_ids=['anyRandomUserX', 'aclUser1'])
        self.acl_list.append(acl_read)
        self._assert_pass_rbac(
            ['admin', 'observer', 'creator', 'audit', 'bogusRole'],
            self._invoke_on_get,
            user_id='aclUser1',
            project_id='different_project_id')
    def test_create_or_replace_from_for_existing_acls(self):
        """Check create_or_replace_from and get count call.

        It modifies existing acls with users and make sure that updated users
        and project_access flag changes are returned when acls are queries by
        secret id. It uses get count to assert expected number of acls for that
        secret.
        """
        session = self.acl_repo.get_session()
        container = self._create_base_container()
        acl1 = self.acl_repo.create_from(
            models.ContainerACL(container.id, 'read'), session)
        self.acl_repo.create_or_replace_from(container,
                                             acl1,
                                             user_ids=['u1', 'u2'],
                                             session=session)

        acl2 = self.acl_repo.create_from(
            models.ContainerACL(container.id, 'write'), session)
        self.acl_repo.create_or_replace_from(container,
                                             acl2,
                                             user_ids=['u1', 'u2', 'u3'],
                                             session=session)

        acl3 = self.acl_repo.create_from(
            models.ContainerACL(container.id, 'list'), session)
        self.acl_repo.create_or_replace_from(container,
                                             acl3,
                                             user_ids=[],
                                             session=session)

        acls = self.acl_repo.get_by_container_id(container.id, session)

        self.assertEqual(3, len(acls))

        id_map = self._map_id_to_acl(acls)
        # replace users in existing acls
        id_map[acl1.id].project_access = False
        self.acl_repo.create_or_replace_from(container,
                                             id_map[acl1.id],
                                             user_ids=['u5'],
                                             session=session)

        self.acl_repo.create_or_replace_from(container,
                                             id_map[acl2.id],
                                             user_ids=['u1', 'u2', 'u3', 'u4'],
                                             session=session)

        self.acl_repo.create_or_replace_from(container,
                                             id_map[acl3.id],
                                             user_ids=['u1', 'u2', 'u4'],
                                             session=session)

        session.commit()
        acls = self.acl_repo.get_by_container_id(container.id, session)
        id_map = self._map_id_to_acl(acls)

        self.assertEqual(3, len(acls))
        self.assertFalse(id_map[acl1.id].project_access)
        self.assertTrue(id_map[acl2.id].project_access)
        self.assertTrue(id_map[acl3.id].project_access)
        self._assert_acl_users(['u5'], acls, acl1.id)
        self._assert_acl_users(['u1', 'u2', 'u3', 'u4'], acls, acl2.id)
        self._assert_acl_users(['u1', 'u2', 'u4'], acls, acl3.id)
 def test_new_containeracl_expect_user_ids_as_list(self):
     acl = models.ContainerACL(self.container_id, self.operation, None,
                               {'aUser': '******'})
     self.assertEqual(0, len(acl.acl_users))
Beispiel #23
0
    def on_put(self, external_project_id, **kwargs):
        """Handles update of existing container acl requests.

        Replaces existing container ACL(s) with input ACL(s) data. Existing
        ACL operation not specified in input are removed as part of update.
        For missing project-access in ACL, true is used as default.
        In update, multiple operation ACL payload can be specified as
        mentioned in sample below. A specific ACL can be updated by its
        own id via ContainerACLController patch request.

        {
          "read":{
            "users":[
              "5ecb18f341894e94baca9e8c7b6a824a",
              "20b63d71f90848cf827ee48074f213b7",
              "c7753f8da8dc4fbea75730ab0b6e0ef4"
            ]
          },
          "write":{
            "users":[
              "5ecb18f341894e94baca9e8c7b6a824a"
            ],
            "project-access":false
          }
        }

        Every container, by default, has an implicit ACL in case client has not
        defined an explicit ACL. That default ACL definition, DEFAULT_ACL,
        signifies that a container by default has project based access i.e.
        client with necessary roles on container project can access the
        container. That's why when ACL is added to a container, it always
        returns 200 (and not 201) indicating existence of implicit ACL on a
        container.
        """

        data = api.load_body(pecan.request, validator=self.validator)
        LOG.debug('Start ContainerACLsController on_put...%s', data)

        existing_acls_map = {
            acl.operation: acl
            for acl in self.container.container_acls
        }
        for operation in itertools.ifilter(lambda x: data.get(x),
                                           validators.ACL_OPERATIONS):
            project_access = data[operation].get('project-access', True)
            user_ids = data[operation].get('users', [])
            if operation in existing_acls_map:  # update if matching acl exists
                c_acl = existing_acls_map.pop(operation)
                c_acl.project_access = project_access
            else:
                c_acl = models.ContainerACL(self.container.id,
                                            operation=operation,
                                            project_access=project_access)
            self.acl_repo.create_or_replace_from(self.container,
                                                 container_acl=c_acl,
                                                 user_ids=user_ids)
        # delete remaining existing acls as they are not present in input.
        for acl in six.itervalues(existing_acls_map):
            self.acl_repo.delete_entity_by_id(entity_id=acl.id,
                                              external_project_id=None)
        acl_ref = '{0}/acl'.format(
            hrefs.convert_container_to_href(self.container.id))
        return {'acl_ref': acl_ref}