Add access rules restriction tests
Adds new test cases and updates current test cases for access allow and deny APIs. Such APIs now allow users to restrict the visibility of some fields during the access creation, or even restricting the deletion of access rules. Depends-On: https://review.opendev.org/c/openstack/manila/+/887725 Change-Id: If0f7655dc6c11c6c12eeb76bd1cc853466235cca
This commit is contained in:
parent
646fcd2e23
commit
d10819b89b
|
@ -40,7 +40,7 @@ ShareGroup = [
|
|||
"This value is only used to validate the versions "
|
||||
"response from Manila."),
|
||||
cfg.StrOpt("max_api_microversion",
|
||||
default="2.81",
|
||||
default="2.82",
|
||||
help="The maximum api microversion is configured to be the "
|
||||
"value of the latest microversion supported by Manila."),
|
||||
cfg.StrOpt("region",
|
||||
|
|
|
@ -764,7 +764,8 @@ class SharesV2Client(shares_client.SharesClient):
|
|||
def create_access_rule(self, share_id, access_type="ip",
|
||||
access_to="0.0.0.0", access_level=None,
|
||||
version=LATEST_MICROVERSION, metadata=None,
|
||||
action_name=None):
|
||||
action_name=None, lock_visibility=False,
|
||||
lock_deletion=False):
|
||||
post_body = {
|
||||
self._get_access_action_name(version, 'os-allow_access'): {
|
||||
"access_type": access_type,
|
||||
|
@ -774,6 +775,10 @@ class SharesV2Client(shares_client.SharesClient):
|
|||
}
|
||||
if metadata is not None:
|
||||
post_body['allow_access']['metadata'] = metadata
|
||||
if lock_visibility:
|
||||
post_body['allow_access']['lock_visibility'] = True
|
||||
if lock_deletion:
|
||||
post_body['allow_access']['lock_deletion'] = True
|
||||
body = json.dumps(post_body)
|
||||
resp, body = self.post(
|
||||
"shares/%s/action" % share_id, body, version=version,
|
||||
|
@ -817,12 +822,15 @@ class SharesV2Client(shares_client.SharesClient):
|
|||
return rest_client.ResponseBody(resp, body)
|
||||
|
||||
def delete_access_rule(self, share_id, rule_id,
|
||||
version=LATEST_MICROVERSION, action_name=None):
|
||||
version=LATEST_MICROVERSION, action_name=None,
|
||||
unrestrict=False):
|
||||
post_body = {
|
||||
self._get_access_action_name(version, 'os-deny_access'): {
|
||||
"access_id": rule_id,
|
||||
}
|
||||
}
|
||||
if unrestrict:
|
||||
post_body['deny_access']['unrestrict'] = True
|
||||
body = json.dumps(post_body)
|
||||
resp, body = self.post(
|
||||
"shares/%s/action" % share_id, body, version=version)
|
||||
|
|
|
@ -1017,7 +1017,8 @@ class BaseSharesTest(test.BaseTestCase):
|
|||
def allow_access(self, share_id, client=None, access_type=None,
|
||||
access_level='rw', access_to=None, metadata=None,
|
||||
version=LATEST_MICROVERSION, status='active',
|
||||
raise_rule_in_error_state=True, cleanup=True):
|
||||
raise_rule_in_error_state=True, lock_visibility=False,
|
||||
lock_deletion=False, cleanup=True):
|
||||
|
||||
client = client or self.shares_v2_client
|
||||
a_type, a_to = utils.get_access_rule_data_from_config(
|
||||
|
@ -1030,8 +1031,15 @@ class BaseSharesTest(test.BaseTestCase):
|
|||
'access_to': access_to,
|
||||
'access_level': access_level
|
||||
}
|
||||
delete_kwargs = (
|
||||
{'unrestrict': True} if lock_deletion else {}
|
||||
)
|
||||
if client is self.shares_v2_client:
|
||||
kwargs.update({'metadata': metadata, 'version': version})
|
||||
if lock_visibility:
|
||||
kwargs.update({'lock_visibility': True})
|
||||
if lock_deletion:
|
||||
kwargs.update({'lock_deletion': True})
|
||||
|
||||
rule = client.create_access_rule(share_id, **kwargs)['access']
|
||||
waiters.wait_for_resource_status(
|
||||
|
@ -1042,7 +1050,9 @@ class BaseSharesTest(test.BaseTestCase):
|
|||
self.addCleanup(
|
||||
client.wait_for_resource_deletion, rule_id=rule['id'],
|
||||
share_id=share_id, version=version)
|
||||
self.addCleanup(client.delete_access_rule, share_id, rule['id'])
|
||||
self.addCleanup(
|
||||
client.delete_access_rule, share_id, rule['id'],
|
||||
**delete_kwargs)
|
||||
return rule
|
||||
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ from manila_tempest_tests import utils
|
|||
|
||||
CONF = config.CONF
|
||||
LATEST_MICROVERSION = CONF.share.max_api_microversion
|
||||
RESTRICTED_RULES_VERSION = '2.82'
|
||||
|
||||
|
||||
def _create_delete_ro_access_rule(self, version):
|
||||
|
@ -444,6 +445,10 @@ class ShareRulesTest(base.BaseSharesMixedTest):
|
|||
cls.share_type = cls.create_share_type()
|
||||
cls.share_type_id = cls.share_type['id']
|
||||
cls.share = cls.create_share(share_type_id=cls.share_type_id)
|
||||
cls.user_project = cls.os_admin.projects_client.show_project(
|
||||
cls.shares_v2_client.project_id)['project']
|
||||
cls.new_user = cls.create_user_and_get_client(
|
||||
project=cls.user_project)
|
||||
|
||||
@decorators.idempotent_id('c52e95cc-d6ea-4d02-9b52-cd7c1913dfff')
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
|
@ -519,6 +524,92 @@ class ShareRulesTest(base.BaseSharesMixedTest):
|
|||
msg = "expected id lists %s times in rule list" % (len(gen))
|
||||
self.assertEqual(1, len(gen), msg)
|
||||
|
||||
@decorators.idempotent_id('3bca373e-e54f-49e1-8789-99a383cf4df3')
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@utils.skip_if_microversion_not_supported(RESTRICTED_RULES_VERSION)
|
||||
@ddt.data(
|
||||
*itertools.product(utils.deduplicate(
|
||||
["2.81", CONF.share.max_api_microversion]), (True, False))
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_list_restricted_rules_from_other_user(
|
||||
self, older_version, lock_visibility):
|
||||
# create rule
|
||||
self.allow_access(
|
||||
self.share["id"], client=self.shares_v2_client,
|
||||
access_type=self.access_type, access_to=self.access_to,
|
||||
lock_visibility=lock_visibility, lock_deletion=True)
|
||||
|
||||
rule = (
|
||||
self.shares_v2_client.list_access_rules(
|
||||
self.share["id"])["access_list"][0])
|
||||
|
||||
rules = self.new_user.shares_v2_client.list_access_rules(
|
||||
self.share['id'])['access_list']
|
||||
rules_get_lower_version = (
|
||||
self.new_user.shares_v2_client.list_access_rules(
|
||||
self.share['id'], version=older_version)['access_list'])
|
||||
expected_access_to = '******' if lock_visibility else self.access_to
|
||||
expected_access_key = (
|
||||
'******' if lock_visibility else rule['access_key'])
|
||||
|
||||
# verify values
|
||||
rule_latest_rules_api = [r for r in rules if r['id'] == rule['id']][0]
|
||||
rule_lower_version_rules_api = [r for r in rules_get_lower_version
|
||||
if r['id'] == rule['id']][0]
|
||||
self.assertEqual(
|
||||
expected_access_to, rule_latest_rules_api["access_to"])
|
||||
self.assertEqual(
|
||||
expected_access_to,
|
||||
rule_lower_version_rules_api['access_to'])
|
||||
if self.access_type == 'cephx':
|
||||
self.assertEqual(expected_access_key,
|
||||
rule_latest_rules_api['access_key'])
|
||||
self.assertEqual(
|
||||
expected_access_key,
|
||||
rule_lower_version_rules_api['access_key'])
|
||||
|
||||
@decorators.idempotent_id('4829265a-eb32-400d-91a0-be06ce31a2ef')
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_admin_listing_restricted_rules(self):
|
||||
utils.check_skip_if_microversion_not_supported(
|
||||
RESTRICTED_RULES_VERSION)
|
||||
|
||||
# create rule
|
||||
self.allow_access(
|
||||
self.share["id"], client=self.shares_v2_client,
|
||||
access_type=self.access_type, access_to=self.access_to,
|
||||
lock_visibility=True)
|
||||
|
||||
rules = self.admin_shares_v2_client.list_access_rules(
|
||||
self.share["id"])['access_list']
|
||||
|
||||
# ensure admin can see rules even if locked
|
||||
self.assertEqual(self.access_to, rules[0]["access_to"])
|
||||
if self.access_type == 'cephx':
|
||||
self.assertIsNotNone(rules[0]['access_key'])
|
||||
self.assertFalse(rules[0]['access_key'] == '******')
|
||||
else:
|
||||
self.assertIsNone(rules[0]['access_key'])
|
||||
|
||||
@decorators.idempotent_id('00202c6c-b4c7-4fa6-933a-562fbffde405')
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_admin_delete_restricted_rules(self):
|
||||
utils.check_skip_if_microversion_not_supported(
|
||||
RESTRICTED_RULES_VERSION)
|
||||
|
||||
# create rule
|
||||
rule = self.allow_access(
|
||||
self.share["id"], client=self.shares_v2_client,
|
||||
access_type=self.access_type, access_to=self.access_to,
|
||||
lock_visibility=True, lock_deletion=True, cleanup=False)
|
||||
|
||||
self.admin_shares_v2_client.delete_access_rule(
|
||||
self.share['id'], rule['id'], unrestrict=True)
|
||||
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
rule_id=rule['id'], share_id=self.share['id'])
|
||||
|
||||
@decorators.idempotent_id('b77bcbda-9754-48f0-9be6-79341ad1af64')
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data(*utils.deduplicate(['1.0', '2.9', '2.27', '2.28',
|
||||
|
|
|
@ -28,6 +28,7 @@ from manila_tempest_tests import utils
|
|||
|
||||
CONF = config.CONF
|
||||
LATEST_MICROVERSION = CONF.share.max_api_microversion
|
||||
RESTRICTED_RULES_VERSION = '2.82'
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
|
@ -60,6 +61,11 @@ class ShareIpRulesForNFSNegativeTest(base.BaseSharesMixedTest):
|
|||
# create snapshot
|
||||
cls.snap = cls.create_snapshot_wait_for_active(cls.share["id"])
|
||||
|
||||
cls.user_project = cls.os_admin.projects_client.show_project(
|
||||
cls.shares_v2_client.project_id)['project']
|
||||
cls.new_user = cls.create_user_and_get_client(
|
||||
project=cls.user_project)
|
||||
|
||||
@decorators.idempotent_id('16781b45-d2bb-4891-aa97-c28c0769d5bd')
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data('1.2.3.256',
|
||||
|
@ -170,6 +176,93 @@ class ShareIpRulesForNFSNegativeTest(base.BaseSharesMixedTest):
|
|||
self.admin_client.create_access_rule,
|
||||
share["id"], access_type, access_to)
|
||||
|
||||
@decorators.idempotent_id('478d3c84-b0ea-41c8-a860-e87f182d991c')
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_deny_access_unrestrict_other_user_rule(self):
|
||||
utils.check_skip_if_microversion_not_supported(
|
||||
RESTRICTED_RULES_VERSION)
|
||||
|
||||
access_type, access_to = utils.get_access_rule_data_from_config(
|
||||
self.protocol)
|
||||
|
||||
# create rule
|
||||
rule = self.allow_access(
|
||||
self.share["id"], client=self.shares_v2_client,
|
||||
access_type=access_type, access_to=access_to,
|
||||
lock_visibility=True, lock_deletion=True)
|
||||
|
||||
self.assertRaises(
|
||||
lib_exc.Forbidden,
|
||||
self.new_user.shares_v2_client.delete_access_rule,
|
||||
self.share['id'],
|
||||
rule['id'],
|
||||
unrestrict=True
|
||||
)
|
||||
|
||||
@decorators.idempotent_id('c107b0b7-7a3e-4114-af64-ca8fe6e836c9')
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
@ddt.data(True, False)
|
||||
def test_deny_access_without_unrestrict_as_owner_user(self, same_user):
|
||||
utils.check_skip_if_microversion_not_supported(
|
||||
RESTRICTED_RULES_VERSION)
|
||||
access_type, access_to = utils.get_access_rule_data_from_config(
|
||||
self.protocol)
|
||||
|
||||
# create rule
|
||||
rule = self.allow_access(
|
||||
self.share["id"], client=self.shares_v2_client,
|
||||
access_type=access_type, access_to=access_to,
|
||||
lock_visibility=True, lock_deletion=True)
|
||||
|
||||
client = (
|
||||
self.shares_v2_client
|
||||
if same_user else self.new_user.shares_v2_client
|
||||
)
|
||||
self.assertRaises(
|
||||
lib_exc.Forbidden,
|
||||
client.delete_access_rule,
|
||||
self.share['id'],
|
||||
rule['id'])
|
||||
self.assertRaises(
|
||||
lib_exc.Forbidden,
|
||||
client.delete_access_rule,
|
||||
self.share['id'],
|
||||
rule['id'],
|
||||
version='2.81'
|
||||
)
|
||||
|
||||
@decorators.idempotent_id('f5b9e7c9-7e6b-4918-a1c4-e03c8d82c46a')
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_allow_access_multiple_visibility_locks_not_allowed(self):
|
||||
utils.check_skip_if_microversion_not_supported(
|
||||
RESTRICTED_RULES_VERSION)
|
||||
access_type, access_to = utils.get_access_rule_data_from_config(
|
||||
self.protocol)
|
||||
|
||||
# create rule
|
||||
rule = self.allow_access(
|
||||
self.share["id"], client=self.shares_v2_client,
|
||||
access_type=access_type, access_to=access_to,
|
||||
lock_visibility=True, lock_deletion=True)
|
||||
|
||||
self.assertRaises(
|
||||
lib_exc.Conflict,
|
||||
self.shares_v2_client.create_resource_lock,
|
||||
rule['id'],
|
||||
"access_rule",
|
||||
resource_action="show",
|
||||
lock_reason="locked for testing"
|
||||
)
|
||||
|
||||
self.assertRaises(
|
||||
lib_exc.Conflict,
|
||||
self.new_user.shares_v2_client.create_resource_lock,
|
||||
rule['id'],
|
||||
"access_rule",
|
||||
resource_action="show",
|
||||
lock_reason="locked for testing"
|
||||
)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareIpRulesForCIFSNegativeTest(ShareIpRulesForNFSNegativeTest):
|
||||
|
|
Loading…
Reference in New Issue