Add ACL and eACL PyTest tests

Signed-off-by: Vladimir Avdeev <v.avdeev@yadro.com>
This commit is contained in:
Vladimir Avdeev 2022-08-25 13:57:55 +03:00 committed by Vladimir Avdeev
parent 590a5cfb0e
commit 6d040c6834
36 changed files with 979 additions and 1318 deletions

View file

@ -0,0 +1,80 @@
from dataclasses import dataclass
from typing import Dict, List, Optional
import allure
import pytest
from common import ASSETS_DIR, IR_WALLET_CONFIG, IR_WALLET_PATH, WALLET_CONFIG
from python_keywords.acl import EACLRole
from python_keywords.container import create_container
from python_keywords.neofs_verbs import put_object
from python_keywords.utility_keywords import generate_file
from wallet import init_wallet
from wellknown_acl import PUBLIC_ACL
OBJECT_COUNT = 5
@dataclass
class Wallet:
wallet_path: Optional[str] = None
config_path: Optional[str] = None
@dataclass
class Wallets:
wallets: Dict[EACLRole, List[Wallet]]
def get_wallet(self, role: EACLRole = EACLRole.USER) -> Wallet:
return self.wallets[role][0]
def get_wallets_list(self, role: EACLRole = EACLRole.USER) -> List[Wallet]:
return self.wallets[role]
@pytest.fixture(scope="module")
def wallets(prepare_wallet_and_deposit):
yield Wallets(wallets={
EACLRole.USER: [
Wallet(
wallet_path=prepare_wallet_and_deposit,
config_path=WALLET_CONFIG
)],
EACLRole.OTHERS: [
Wallet(
wallet_path=init_wallet(ASSETS_DIR)[0],
config_path=WALLET_CONFIG
),
Wallet(
wallet_path=init_wallet(ASSETS_DIR)[0],
config_path=WALLET_CONFIG
)],
EACLRole.SYSTEM: [
Wallet(
wallet_path=IR_WALLET_PATH,
config_path=IR_WALLET_CONFIG
)],
})
@pytest.fixture(scope="module")
def file_path():
yield generate_file()
@pytest.fixture(scope='function')
def eacl_container_with_objects(wallets, file_path):
user_wallet = wallets.get_wallet()
with allure.step('Create eACL public container'):
cid = create_container(user_wallet.wallet_path, basic_acl=PUBLIC_ACL)
with allure.step('Add test objects to container'):
objects_oids = [
put_object(
user_wallet.wallet_path, file_path, cid,
attributes={'key1': 'val1', 'key': val, 'key2': 'abc'}) for val in range(OBJECT_COUNT)]
yield cid, objects_oids, file_path
# with allure.step('Delete eACL public container'):
# delete_container(user_wallet, cid)

View file

@ -1,117 +1,102 @@
import os
from typing import Tuple
import allure
import pytest
import wallet
from common import ASSETS_DIR
from grpc_responses import OBJECT_ACCESS_DENIED
from python_keywords.acl import set_eacl
from python_keywords.acl import EACLRole
from python_keywords.container import create_container
from python_keywords.neofs_verbs import (delete_object, get_object, get_range,
get_range_hash, head_object,
put_object, search_object)
from python_keywords.utility_keywords import generate_file, get_file_hash
RESOURCE_DIR = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
'../../../robot/resources/files/',
)
from python_keywords.container_access import (check_full_access_to_container, check_no_access_to_container,
check_read_only_container)
from python_keywords.neofs_verbs import put_object
from wellknown_acl import PRIVATE_ACL_F, PUBLIC_ACL_F, READONLY_ACL_F
@pytest.mark.sanity
@pytest.mark.acl
class TestACL:
@pytest.fixture(autouse=True)
def create_two_wallets(self, prepare_wallet_and_deposit):
self.main_wallet = prepare_wallet_and_deposit
self.other_wallet = wallet.init_wallet(ASSETS_DIR)[0] # We need wallet file path only
@pytest.mark.acl_container
class TestACLBasic:
@allure.title('Test basic ACL')
def test_basic_acl(self):
@pytest.fixture(scope='function')
def public_container(self, wallets):
user_wallet = wallets.get_wallet()
with allure.step('Create public container'):
cid_public = create_container(user_wallet.wallet_path, basic_acl=PUBLIC_ACL_F)
yield cid_public
# with allure.step('Delete public container'):
# delete_container(user_wallet.wallet_path, cid_public)
@pytest.fixture(scope='function')
def private_container(self, wallets):
user_wallet = wallets.get_wallet()
with allure.step('Create private container'):
cid_private = create_container(user_wallet.wallet_path, basic_acl=PRIVATE_ACL_F)
yield cid_private
# with allure.step('Delete private container'):
# delete_container(user_wallet.wallet_path, cid_private)
@pytest.fixture(scope='function')
def read_only_container(self, wallets):
user_wallet = wallets.get_wallet()
with allure.step('Create public readonly container'):
cid_read_only = create_container(user_wallet.wallet_path, basic_acl=READONLY_ACL_F)
yield cid_read_only
# with allure.step('Delete public readonly container'):
# delete_container(user_wallet.wallet_path, cid_read_only)
@allure.title('Test basic ACL on public container')
def test_basic_acl_public(self, wallets, public_container, file_path):
"""
Test basic ACL set during container creation.
Test basic ACL set during public container creation.
"""
file_name = generate_file()
user_wallet = wallets.get_wallet()
other_wallet = wallets.get_wallet(role=EACLRole.OTHERS)
cid = public_container
for wallet, desc in ((user_wallet, 'owner'), (other_wallet, 'other users')):
with allure.step('Add test objects to container'):
# We create new objects for each wallet because check_full_access_to_container deletes the object
owner_object_oid = put_object(user_wallet.wallet_path, file_path, cid, attributes={'created': 'owner'})
other_object_oid = put_object(other_wallet.wallet_path, file_path, cid, attributes={'created': 'other'})
with allure.step(f'Check {desc} has full access to public container'):
check_full_access_to_container(wallet.wallet_path, cid, owner_object_oid, file_path)
check_full_access_to_container(wallet.wallet_path, cid, other_object_oid, file_path)
with allure.step('Create public container and check access'):
cid_public = create_container(self.main_wallet, basic_acl='public-read-write')
self.check_full_access(cid_public, file_name)
with allure.step('Create private container and check only owner has access'):
cid_private = create_container(self.main_wallet, basic_acl='private')
with allure.step('Check owner can put/get object into private container'):
oid = put_object(wallet=self.main_wallet, path=file_name, cid=cid_private)
got_file = get_object(self.main_wallet, cid_private, oid)
assert get_file_hash(got_file) == get_file_hash(file_name)
@allure.title('Test basic ACL on private container')
def test_basic_acl_private(self, wallets, private_container, file_path):
"""
Test basic ACL set during private container creation.
"""
user_wallet = wallets.get_wallet()
other_wallet = wallets.get_wallet(role=EACLRole.OTHERS)
cid = private_container
with allure.step('Add test objects to container'):
owner_object_oid = put_object(user_wallet.wallet_path, file_path, cid)
with allure.step('Check only owner has full access to private container'):
with allure.step('Check no one except owner has access to operations with container'):
self.check_no_access_to_container(self.other_wallet, cid_private, oid, file_name)
check_no_access_to_container(other_wallet.wallet_path, cid, owner_object_oid, file_path)
delete_object(self.main_wallet, cid_private, oid)
with allure.step('Check owner has full access to private container'):
check_full_access_to_container(
user_wallet.wallet_path, cid, owner_object_oid, file_path)
@allure.title('Test extended ACL')
def test_extended_acl(self):
@allure.title('Test basic ACL on readonly container')
def test_basic_acl_readonly(self, wallets, read_only_container, file_path):
"""
Test basic extended ACL applied after container creation.
Test basic ACL Operations for Read-Only Container.
"""
file_name = generate_file()
deny_all_eacl = os.path.join(RESOURCE_DIR, 'eacl_tables/gen_eacl_deny_all_OTHERS')
user_wallet = wallets.get_wallet()
other_wallet = wallets.get_wallet(role=EACLRole.OTHERS)
cid = read_only_container
with allure.step('Create public container and check access'):
cid_public = create_container(self.main_wallet, basic_acl='eacl-public-read-write')
oid = self.check_full_access(cid_public, file_name)
with allure.step('Add test objects to container'):
object_oid = put_object(user_wallet.wallet_path, file_path, cid)
with allure.step('Set "deny all operations for other" for created container'):
set_eacl(self.main_wallet, cid_public, deny_all_eacl)
with allure.step('Check other has read-only access to operations with container'):
check_read_only_container(other_wallet.wallet_path, cid, object_oid, file_path)
with allure.step('Check no one except owner has access to operations with container'):
self.check_no_access_to_container(self.other_wallet, cid_public, oid, file_name)
with allure.step('Check owner has access to operations with container'):
self.check_full_access(cid_public, file_name, wallet_to_check=((self.main_wallet, 'owner'),))
delete_object(self.main_wallet, cid_public, oid)
@staticmethod
def check_no_access_to_container(wallet: str, cid: str, oid: str, file_name: str):
with pytest.raises(Exception, match=OBJECT_ACCESS_DENIED):
get_object(wallet, cid, oid)
with pytest.raises(Exception, match=OBJECT_ACCESS_DENIED):
put_object(wallet, file_name, cid)
with pytest.raises(Exception, match=OBJECT_ACCESS_DENIED):
delete_object(wallet, cid, oid)
with pytest.raises(Exception, match=OBJECT_ACCESS_DENIED):
head_object(wallet, cid, oid)
with pytest.raises(Exception, match=OBJECT_ACCESS_DENIED):
get_range(wallet, cid, oid, bearer='', range_cut='0:10')
with pytest.raises(Exception, match=OBJECT_ACCESS_DENIED):
get_range_hash(wallet, cid, oid, bearer_token='', range_cut='0:10')
with pytest.raises(Exception, match=OBJECT_ACCESS_DENIED):
search_object(wallet, cid)
def check_full_access(self, cid: str, file_name: str, wallet_to_check: Tuple = None) -> str:
wallets = wallet_to_check or ((self.main_wallet, 'owner'), (self.other_wallet, 'not owner'))
for current_wallet, desc in wallets:
with allure.step(f'Check {desc} can put object into public container'):
oid = put_object(current_wallet, file_name, cid)
with allure.step(f'Check {desc} can execute operations on object from public container'):
got_file = get_object(current_wallet, cid, oid)
assert get_file_hash(got_file) == get_file_hash(file_name), 'Expected hashes are the same'
head_object(current_wallet, cid, oid)
get_range(current_wallet, cid, oid, bearer='', range_cut='0:10')
get_range_hash(current_wallet, cid, oid, bearer_token='', range_cut='0:10')
search_object(current_wallet, cid)
return oid
with allure.step('Check owner has full access to public container'):
check_full_access_to_container(user_wallet.wallet_path, cid, object_oid, file_path)

View file

@ -0,0 +1,108 @@
import allure
import pytest
from python_keywords.acl import (EACLAccess, EACLOperation, EACLRole, EACLRule, create_eacl, form_bearertoken_file,
set_eacl, wait_for_cache_expired)
from python_keywords.container_access import (check_custom_access_to_container, check_full_access_to_container,
check_no_access_to_container)
@pytest.mark.sanity
@pytest.mark.acl
@pytest.mark.acl_bearer
class TestACLBearer:
@pytest.mark.parametrize('role', [EACLRole.USER, EACLRole.OTHERS])
def test_bearer_token_operations(self, wallets, eacl_container_with_objects, role):
allure.dynamic.title(f"Testcase to validate NeoFS operations with {role.value} BearerToken")
cid, objects_oids, file_path = eacl_container_with_objects
user_wallet = wallets.get_wallet()
deny_wallet = wallets.get_wallet(role)
with allure.step(f'Check {role.value} has full access to container without bearer token'):
check_full_access_to_container(deny_wallet.wallet_path, cid, objects_oids.pop(), file_path,
wallet_config=deny_wallet.config_path)
with allure.step(f'Set deny all operations for {role.value} via eACL'):
eacl = [EACLRule(access=EACLAccess.DENY, role=role, operation=op) for op in EACLOperation]
eacl_file = create_eacl(cid, eacl)
set_eacl(user_wallet.wallet_path, cid, eacl_file)
wait_for_cache_expired()
with allure.step(f'Create bearer token for {role.value} with all operations allowed'):
bearer_token = form_bearertoken_file(user_wallet.wallet_path, cid, [
EACLRule(operation=op, access=EACLAccess.ALLOW, role=role)
for op in EACLOperation])
with allure.step(f'Check {role.value} without token has no access to all operations with container'):
check_no_access_to_container(
deny_wallet.wallet_path, cid, objects_oids.pop(), file_path,
wallet_config=deny_wallet.config_path)
with allure.step(f'Check {role.value} with token has access to all operations with container'):
check_full_access_to_container(deny_wallet.wallet_path, cid, objects_oids.pop(), file_path,
bearer=bearer_token, wallet_config=deny_wallet.config_path)
with allure.step(f'Set allow all operations for {role.value} via eACL'):
eacl = [EACLRule(access=EACLAccess.ALLOW, role=role, operation=op) for op in EACLOperation]
eacl_file = create_eacl(cid, eacl)
set_eacl(user_wallet.wallet_path, cid, eacl_file)
wait_for_cache_expired()
with allure.step(f'Check {role.value} without token has access to all operations with container'):
check_full_access_to_container(deny_wallet.wallet_path, cid, objects_oids.pop(), file_path,
wallet_config=deny_wallet.config_path)
@allure.title('BearerToken Operations for compound Operations')
def test_bearer_token_compound_operations(self, wallets, eacl_container_with_objects):
cid, objects_oids, file_path = eacl_container_with_objects
user_wallet = wallets.get_wallet()
other_wallet = wallets.get_wallet(role=EACLRole.OTHERS)
# Operations that we will deny for each role via eACL
deny_map = {
EACLRole.USER: [EACLOperation.DELETE],
EACLRole.OTHERS: [EACLOperation.GET, EACLOperation.PUT, EACLOperation.GET_RANGE]
}
# Operations that we will allow for each role with bearer token
bearer_map = {
EACLRole.USER: [EACLOperation.DELETE, EACLOperation.PUT, EACLOperation.GET_RANGE],
EACLRole.OTHERS: [EACLOperation.GET, EACLOperation.GET_RANGE],
}
deny_map_with_bearer = {
EACLRole.USER: [op for op in deny_map[EACLRole.USER] if op not in bearer_map[EACLRole.USER]],
EACLRole.OTHERS: [op for op in deny_map[EACLRole.OTHERS] if op not in bearer_map[EACLRole.OTHERS]],
}
eacl_deny = []
for role, operations in deny_map.items():
eacl_deny += [EACLRule(access=EACLAccess.DENY, role=role, operation=op) for op in operations]
set_eacl(user_wallet.wallet_path, cid, eacl_table_path=create_eacl(cid, eacl_deny))
wait_for_cache_expired()
with allure.step('Check rule consistency without bearer'):
check_custom_access_to_container(user_wallet.wallet_path, cid, objects_oids.pop(), file_path,
deny_operations=deny_map[EACLRole.USER],
wallet_config=user_wallet.config_path)
check_custom_access_to_container(other_wallet.wallet_path, cid, objects_oids.pop(), file_path,
deny_operations=deny_map[EACLRole.OTHERS],
wallet_config=other_wallet.config_path)
with allure.step('Check rule consistency with bearer'):
bearer_token_user = form_bearertoken_file(user_wallet.wallet_path, cid, [
EACLRule(operation=op, access=EACLAccess.ALLOW, role=EACLRole.USER)
for op in bearer_map[EACLRole.USER]])
bearer_token_other = form_bearertoken_file(user_wallet.wallet_path, cid, [
EACLRule(operation=op, access=EACLAccess.ALLOW, role=EACLRole.OTHERS)
for op in bearer_map[EACLRole.OTHERS]])
check_custom_access_to_container(user_wallet.wallet_path, cid, objects_oids.pop(), file_path,
deny_operations=deny_map_with_bearer[EACLRole.USER],
bearer=bearer_token_user,
wallet_config=user_wallet.config_path)
check_custom_access_to_container(other_wallet.wallet_path, cid, objects_oids.pop(), file_path,
deny_operations=deny_map_with_bearer[EACLRole.OTHERS],
bearer=bearer_token_other,
wallet_config=other_wallet.config_path)

View file

@ -0,0 +1,105 @@
import allure
import pytest
from common import NEOFS_NETMAP_DICT
from failover_utils import wait_object_replication_on_nodes
from python_keywords.acl import (EACLAccess, EACLOperation, EACLRole, EACLRule, create_eacl, set_eacl,
wait_for_cache_expired)
from python_keywords.container import create_container
from python_keywords.container_access import check_full_access_to_container, check_no_access_to_container
from python_keywords.neofs_verbs import put_object
from python_keywords.node_management import drop_object
from wellknown_acl import PUBLIC_ACL
@pytest.mark.sanity
@pytest.mark.acl
@pytest.mark.acl_container
class TestEACLContainer:
NODE_COUNT = len(NEOFS_NETMAP_DICT.keys())
@pytest.fixture(scope='function')
def eacl_full_placement_container_with_object(self, wallets, file_path):
user_wallet = wallets.get_wallet()
with allure.step('Create eACL public container with full placement rule'):
full_placement_rule = f'REP {self.NODE_COUNT} IN X CBF 1 SELECT {self.NODE_COUNT} FROM * AS X'
cid = create_container(user_wallet.wallet_path, full_placement_rule, basic_acl=PUBLIC_ACL)
with allure.step('Add test object to container'):
oid = put_object(user_wallet.wallet_path, file_path, cid)
wait_object_replication_on_nodes(user_wallet.wallet_path, cid, oid, self.NODE_COUNT)
yield cid, oid, file_path
@pytest.mark.parametrize('deny_role', [EACLRole.USER, EACLRole.OTHERS])
def test_extended_acl_deny_all_operations(self, wallets, eacl_container_with_objects, deny_role):
user_wallet = wallets.get_wallet()
other_wallet = wallets.get_wallet(EACLRole.OTHERS)
deny_role_wallet = other_wallet if deny_role == EACLRole.OTHERS else user_wallet
not_deny_role_wallet = user_wallet if deny_role == EACLRole.OTHERS else other_wallet
deny_role_str = 'all others' if deny_role == EACLRole.OTHERS else 'user'
not_deny_role_str = 'user' if deny_role == EACLRole.OTHERS else 'all others'
allure.dynamic.title(f'Testcase to deny NeoFS operations for {deny_role_str}.')
cid, object_oids, file_path = eacl_container_with_objects
with allure.step(f'Deny all operations for {deny_role_str} via eACL'):
eacl_deny = [EACLRule(access=EACLAccess.DENY, role=deny_role, operation=op) for op in EACLOperation]
set_eacl(user_wallet.wallet_path, cid, create_eacl(cid, eacl_deny))
wait_for_cache_expired()
with allure.step(f'Check only {not_deny_role_str} has full access to container'):
with allure.step(f'Check {deny_role_str} has not access to any operations with container'):
check_no_access_to_container(deny_role_wallet.wallet_path, cid, object_oids[0], file_path)
with allure.step(f'Check {not_deny_role_wallet} has full access to eACL public container'):
check_full_access_to_container(not_deny_role_wallet.wallet_path, cid, object_oids.pop(), file_path)
with allure.step(f'Allow all operations for {deny_role_str} via eACL'):
eacl_deny = [EACLRule(access=EACLAccess.ALLOW, role=deny_role, operation=op) for op in EACLOperation]
set_eacl(user_wallet.wallet_path, cid, create_eacl(cid, eacl_deny))
wait_for_cache_expired()
with allure.step(f'Check all have full access to eACL public container'):
check_full_access_to_container(user_wallet.wallet_path, cid, object_oids.pop(), file_path)
check_full_access_to_container(other_wallet.wallet_path, cid, object_oids.pop(), file_path)
@allure.title('Testcase to allow NeoFS operations for only one other pubkey.')
def test_extended_acl_deny_all_operations_exclude_pubkey(self, wallets, eacl_container_with_objects):
user_wallet = wallets.get_wallet()
other_wallet, other_wallet_allow = wallets.get_wallets_list(EACLRole.OTHERS)[0:2]
cid, object_oids, file_path = eacl_container_with_objects
with allure.step('Deny all operations for others except single wallet via eACL'):
eacl = [EACLRule(access=EACLAccess.ALLOW, role=other_wallet_allow.wallet_path, operation=op)
for op in EACLOperation]
eacl += [EACLRule(access=EACLAccess.DENY, role=EACLRole.OTHERS, operation=op) for op in EACLOperation]
set_eacl(user_wallet.wallet_path, cid, create_eacl(cid, eacl))
wait_for_cache_expired()
with allure.step('Check only owner and allowed other have full access to public container'):
with allure.step('Check other has not access to operations with container'):
check_no_access_to_container(other_wallet.wallet_path, cid, object_oids[0], file_path)
with allure.step('Check owner has full access to public container'):
check_full_access_to_container(user_wallet.wallet_path, cid, object_oids.pop(), file_path)
with allure.step('Check allowed other has full access to public container'):
check_full_access_to_container(other_wallet_allow.wallet_path, cid, object_oids.pop(), file_path)
@allure.title('Testcase to validate NeoFS replication with eACL deny rules.')
def test_extended_acl_deny_replication(self, wallets, eacl_full_placement_container_with_object, file_path):
user_wallet = wallets.get_wallet()
cid, oid, file_path = eacl_full_placement_container_with_object
with allure.step('Deny all operations for user via eACL'):
eacl_deny = [EACLRule(access=EACLAccess.DENY, role=EACLRole.USER, operation=op) for op in EACLOperation]
eacl_deny += [EACLRule(access=EACLAccess.DENY, role=EACLRole.OTHERS, operation=op) for op in EACLOperation]
set_eacl(user_wallet.wallet_path, cid, create_eacl(cid, eacl_deny))
wait_for_cache_expired()
with allure.step('Drop object to check replication'):
drop_object(node_name=[*NEOFS_NETMAP_DICT][0], cid=cid, oid=oid)
storage_wallet_path = NEOFS_NETMAP_DICT[[*NEOFS_NETMAP_DICT][0]]["wallet_path"]
with allure.step('Wait for dropped object replicated'):
wait_object_replication_on_nodes(storage_wallet_path, cid, oid, self.NODE_COUNT)

View file

@ -0,0 +1,197 @@
import allure
import pytest
from python_keywords.acl import (EACLAccess, EACLFilter, EACLFilters, EACLHeaderType, EACLMatchType, EACLOperation,
EACLRole, EACLRule, create_eacl, set_eacl, wait_for_cache_expired)
from python_keywords.container import create_container, delete_container
from python_keywords.container_access import check_full_access_to_container, check_no_access_to_container
from python_keywords.neofs_verbs import put_object
from python_keywords.object_access import can_get_object, can_get_head_object, can_put_object
from wellknown_acl import PUBLIC_ACL
@pytest.mark.sanity
@pytest.mark.acl
@pytest.mark.acl_container
class TestEACLFilters:
# SPEC: https://github.com/nspcc-dev/neofs-spec/blob/master/01-arch/07-acl.md
ATTRIBUTE = {'check_key': 'check_value'}
OTHER_ATTRIBUTE = {'check_key': 'other_value'}
SET_HEADERS = {'key_one': 'check_value', 'x_key': 'xvalue', 'check_key': 'check_value'}
OTHER_HEADERS = {'key_one': 'check_value', 'x_key': 'other_value', 'check_key': 'other_value'}
REQ_EQUAL_FILTER = EACLFilter(key='check_key', value='check_value', header_type=EACLHeaderType.REQUEST)
NOT_REQ_EQUAL_FILTER = EACLFilter(key='check_key', value='other_value', match_type=EACLMatchType.STRING_NOT_EQUAL,
header_type=EACLHeaderType.REQUEST)
OBJ_EQUAL_FILTER = EACLFilter(key='check_key', value='check_value', header_type=EACLHeaderType.OBJECT)
NOT_OBJ_EQUAL_FILTER = EACLFilter(key='check_key', value='other_value', match_type=EACLMatchType.STRING_NOT_EQUAL,
header_type=EACLHeaderType.OBJECT)
OBJECT_COUNT = 3
OBJECT_ATTRIBUTES_FILTER_SUPPORTED_OPERATIONS = [EACLOperation.GET, EACLOperation.HEAD, EACLOperation.PUT]
@pytest.fixture(scope='function')
def eacl_container_with_objects(self, wallets, file_path):
user_wallet = wallets.get_wallet()
with allure.step('Create eACL public container'):
cid = create_container(user_wallet.wallet_path, basic_acl=PUBLIC_ACL)
with allure.step('Add test objects to container'):
objects_with_header = [
put_object(user_wallet.wallet_path, file_path, cid,
attributes={**self.SET_HEADERS, 'key': val}) for val in range(self.OBJECT_COUNT)]
objects_with_other_header = [
put_object(user_wallet.wallet_path, file_path, cid,
attributes={**self.OTHER_HEADERS, 'key': val}) for val in range(self.OBJECT_COUNT)]
objects_without_header = [
put_object(user_wallet.wallet_path, file_path, cid) for _ in range(self.OBJECT_COUNT)]
yield cid, objects_with_header, objects_with_other_header, objects_without_header, file_path
with allure.step('Delete eACL public container'):
delete_container(user_wallet.wallet_path, cid)
@pytest.mark.parametrize('match_type', [EACLMatchType.STRING_EQUAL, EACLMatchType.STRING_NOT_EQUAL])
def test_extended_acl_filters_request(self, wallets, eacl_container_with_objects, match_type):
allure.dynamic.title(f"Validate NeoFS operations with request filter: {match_type.name}")
user_wallet = wallets.get_wallet()
other_wallet = wallets.get_wallet(EACLRole.OTHERS)
cid, objects_with_header, objects_with_other_header, objects_without_header, file_path =\
eacl_container_with_objects
with allure.step('Deny all operations for other with eACL request filter'):
equal_filter = EACLFilter(**self.REQ_EQUAL_FILTER.__dict__)
equal_filter.match_type = match_type
eacl_deny = [EACLRule(access=EACLAccess.DENY,
role=EACLRole.OTHERS,
filters=EACLFilters([equal_filter]),
operation=op) for op in EACLOperation]
set_eacl(user_wallet.wallet_path, cid, create_eacl(cid, eacl_deny))
wait_for_cache_expired()
# Filter denies requests where "check_key {match_type} ATTRIBUTE", so when match_type
# is STRING_EQUAL, then requests with "check_key=OTHER_ATTRIBUTE" will be allowed while
# requests with "check_key=ATTRIBUTE" will be denied, and vice versa
allow_headers = self.OTHER_ATTRIBUTE if match_type == EACLMatchType.STRING_EQUAL else self.ATTRIBUTE
deny_headers = self.ATTRIBUTE if match_type == EACLMatchType.STRING_EQUAL else self.OTHER_ATTRIBUTE
# We test on 3 groups of objects with various headers, but eACL rule should ignore object headers and
# work only based on request headers
for oid in (objects_with_header, objects_with_other_header, objects_without_header):
with allure.step('Check other has full access when sending request without headers'):
check_full_access_to_container(other_wallet.wallet_path, cid, oid.pop(), file_path)
with allure.step('Check other has full access when sending request with allowed headers'):
check_full_access_to_container(other_wallet.wallet_path, cid, oid.pop(), file_path, xhdr=allow_headers)
with allure.step('Check other has no access when sending request with denied headers'):
check_no_access_to_container(other_wallet.wallet_path, cid, oid.pop(), file_path, xhdr=deny_headers)
@pytest.mark.parametrize('match_type', [EACLMatchType.STRING_EQUAL, EACLMatchType.STRING_NOT_EQUAL])
def test_extended_acl_deny_filters_object(self, wallets, eacl_container_with_objects, match_type):
allure.dynamic.title(f"Validate NeoFS operations with deny user headers filter: {match_type.name}")
user_wallet = wallets.get_wallet()
other_wallet = wallets.get_wallet(EACLRole.OTHERS)
cid, objects_with_header, objects_with_other_header, objs_without_header, file_path = \
eacl_container_with_objects
with allure.step('Deny all operations for other with object filter'):
equal_filter = EACLFilter(**self.OBJ_EQUAL_FILTER.__dict__)
equal_filter.match_type = match_type
eacl_deny = [EACLRule(access=EACLAccess.DENY,
role=EACLRole.OTHERS,
filters=EACLFilters([equal_filter]),
operation=op) for op in self.OBJECT_ATTRIBUTES_FILTER_SUPPORTED_OPERATIONS]
set_eacl(user_wallet.wallet_path, cid, create_eacl(cid, eacl_deny))
wait_for_cache_expired()
allow_objects = objects_with_other_header if match_type == EACLMatchType.STRING_EQUAL else objects_with_header
deny_objects = objects_with_header if match_type == EACLMatchType.STRING_EQUAL else objects_with_other_header
# We will attempt requests with various headers, but eACL rule should ignore request headers and validate
# only object headers
for xhdr in (self.ATTRIBUTE, self.OTHER_ATTRIBUTE, None):
with allure.step(f'Check other have full access to objects without attributes'):
check_full_access_to_container(
other_wallet.wallet_path, cid, objs_without_header.pop(), file_path, xhdr=xhdr)
with allure.step(f'Check other have full access to objects without deny attribute'):
check_full_access_to_container(
other_wallet.wallet_path, cid, allow_objects.pop(), file_path, xhdr=xhdr)
with allure.step(f'Check other have no access to objects with deny attribute'):
oid = deny_objects.pop()
with pytest.raises(AssertionError):
assert can_get_head_object(other_wallet.wallet_path, cid, oid, xhdr=xhdr)
with pytest.raises(AssertionError):
assert can_get_object(other_wallet.wallet_path, cid, oid, file_path, xhdr=xhdr)
allow_attribute = self.OTHER_ATTRIBUTE if match_type == EACLMatchType.STRING_EQUAL else self.ATTRIBUTE
with allure.step('Check other can PUT objects without denied attribute'):
assert can_put_object(other_wallet.wallet_path, cid, file_path, attributes=allow_attribute)
assert can_put_object(other_wallet.wallet_path, cid, file_path)
deny_attribute = self.ATTRIBUTE if match_type == EACLMatchType.STRING_EQUAL else self.OTHER_ATTRIBUTE
with allure.step('Check other can not PUT objects with denied attribute'):
with pytest.raises(AssertionError):
assert can_put_object(other_wallet.wallet_path, cid, file_path, attributes=deny_attribute)
@pytest.mark.parametrize('match_type', [EACLMatchType.STRING_EQUAL, EACLMatchType.STRING_NOT_EQUAL])
def test_extended_acl_allow_filters_object(self, wallets, eacl_container_with_objects, match_type):
allure.dynamic.title(
f"Testcase to validate NeoFS operation with allow eACL user headers filters: {match_type.name}")
user_wallet = wallets.get_wallet()
other_wallet = wallets.get_wallet(EACLRole.OTHERS)
cid, objects_with_header, objects_with_other_header, objects_without_header, file_path = \
eacl_container_with_objects
with allure.step('Deny all operations for others except few operations allowed by object filter'):
equal_filter = EACLFilter(**self.OBJ_EQUAL_FILTER.__dict__)
equal_filter.match_type = match_type
eacl = [
EACLRule(access=EACLAccess.ALLOW,
role=EACLRole.OTHERS,
filters=EACLFilters([equal_filter]),
operation=op) for op in self.OBJECT_ATTRIBUTES_FILTER_SUPPORTED_OPERATIONS
] + [
EACLRule(access=EACLAccess.DENY,
role=EACLRole.OTHERS,
operation=op) for op in self.OBJECT_ATTRIBUTES_FILTER_SUPPORTED_OPERATIONS
]
set_eacl(user_wallet.wallet_path, cid, create_eacl(cid, eacl))
wait_for_cache_expired()
if match_type == EACLMatchType.STRING_EQUAL:
allow_objects = objects_with_header
deny_objects = objects_with_other_header
allow_attribute = self.ATTRIBUTE
deny_attribute = self.OTHER_ATTRIBUTE
else:
allow_objects = objects_with_other_header
deny_objects = objects_with_header
allow_attribute = self.OTHER_ATTRIBUTE
deny_attribute = self.ATTRIBUTE
with allure.step(f'Check other cannot get and put objects without attributes'):
oid = objects_without_header.pop()
with pytest.raises(AssertionError):
assert can_get_head_object(other_wallet.wallet_path, cid, oid)
with pytest.raises(AssertionError):
assert can_get_object(other_wallet.wallet_path, cid, oid, file_path)
with pytest.raises(AssertionError):
assert can_put_object(other_wallet.wallet_path, cid, file_path)
with allure.step(f'Check other can get objects with attributes matching the filter'):
oid = allow_objects.pop()
assert can_get_head_object(other_wallet.wallet_path, cid, oid)
assert can_get_object(other_wallet.wallet_path, cid, oid, file_path)
assert can_put_object(other_wallet.wallet_path, cid, file_path, attributes=allow_attribute)
with allure.step(f'Check other cannot get objects without attributes matching the filter'):
oid = deny_objects.pop()
with pytest.raises(AssertionError):
assert can_get_head_object(other_wallet.wallet_path, cid, oid)
with pytest.raises(AssertionError):
assert can_get_object(other_wallet.wallet_path, cid, oid, file_path)
with pytest.raises(AssertionError):
assert can_put_object(other_wallet.wallet_path, cid, file_path, attributes=deny_attribute)

View file

@ -3,7 +3,6 @@ import json
import allure
import pytest
from epoch import tick_epoch
from grpc_responses import CONTAINER_NOT_FOUND, error_matches_status
from python_keywords.container import (create_container, delete_container, get_container, list_containers,
wait_for_container_creation, wait_for_container_deletion)
from utility import placement_policy_from_container
@ -28,7 +27,7 @@ def test_container_creation(prepare_wallet_and_deposit, name):
assert cid in containers, f'Expected container {cid} in containers: {containers}'
container_info: str = get_container(wallet, cid, json_mode=False)
container_info = container_info.casefold() # To ignore case when comparing with expected values
container_info = container_info.casefold() # To ignore case when comparing with expected values
info_to_check = {
f'basic ACL: {PRIVATE_ACL_F} (private)',

View file

@ -45,8 +45,8 @@ def test_object_api(prepare_wallet_and_deposit, request, object_size):
with allure.step('Put objects'):
oids.append(put_object(wallet=wallet, path=file_path, cid=cid))
oids.append(put_object(wallet=wallet, path=file_path, cid=cid, user_headers=file_usr_header))
oids.append(put_object(wallet=wallet, path=file_path, cid=cid, user_headers=file_usr_header_oth))
oids.append(put_object(wallet=wallet, path=file_path, cid=cid, attributes=file_usr_header))
oids.append(put_object(wallet=wallet, path=file_path, cid=cid, attributes=file_usr_header_oth))
with allure.step('Validate storage policy for objects'):
for oid_to_check in oids: