a.berezin
4eef2f2437
All checks were successful
DCO check / DCO (pull_request) Successful in 1m50s
Signed-off-by: a.berezin <a.berezin@yadro.com>
196 lines
8.2 KiB
Python
196 lines
8.2 KiB
Python
import allure
|
|
import pytest
|
|
from frostfs_testlib import reporter
|
|
from frostfs_testlib.cli.frostfs_cli.cli import FrostfsCli
|
|
from frostfs_testlib.storage.dataclasses import ape
|
|
from frostfs_testlib.storage.dataclasses.wallet import WalletInfo
|
|
from frostfs_testlib.testing.cluster_test_base import ClusterTestBase
|
|
from frostfs_testlib.utils.file_utils import TestFile
|
|
|
|
from ....helpers.bearer_token import create_bearer_token
|
|
from ....helpers.container_access import (
|
|
ALL_OBJECT_OPERATIONS,
|
|
assert_access_to_container,
|
|
assert_full_access_to_container,
|
|
assert_no_access_to_container,
|
|
)
|
|
|
|
|
|
@pytest.mark.nightly
|
|
@pytest.mark.sanity
|
|
@pytest.mark.bearer
|
|
@pytest.mark.ape
|
|
@pytest.mark.parametrize("user_tag", ["ApeBearer"], indirect=True) # provide dedicated user with no APE side-policies
|
|
class TestApeBearer(ClusterTestBase):
|
|
@allure.title("Operations with BearerToken (role={role}, obj_size={object_size})")
|
|
@pytest.mark.parametrize("role", [ape.Role.OWNER, ape.Role.OTHERS], indirect=True)
|
|
def test_bearer_token_operations(
|
|
self,
|
|
container: str,
|
|
objects: list[str],
|
|
frostfs_cli: FrostfsCli,
|
|
temp_directory: str,
|
|
test_wallet: WalletInfo,
|
|
role: ape.Role,
|
|
file_path: TestFile,
|
|
rpc_endpoint: str,
|
|
):
|
|
with reporter.step(f"Check {role} has full access to container without bearer token"):
|
|
assert_full_access_to_container(test_wallet, container, objects.pop(), file_path, self.shell, self.cluster)
|
|
|
|
with reporter.step(f"Deny all operations for everyone via APE"):
|
|
rule = ape.Rule(ape.Verb.DENY, ALL_OBJECT_OPERATIONS)
|
|
frostfs_cli.ape_manager.add(rpc_endpoint, rule.chain_id, target_name=container, target_type="container", rule=rule.as_string())
|
|
|
|
with reporter.step("Wait for one block"):
|
|
self.wait_for_blocks()
|
|
|
|
with reporter.step(f"Create bearer token with all operations allowed"):
|
|
bearer = create_bearer_token(
|
|
frostfs_cli,
|
|
temp_directory,
|
|
container,
|
|
rule=ape.Rule(ape.Verb.ALLOW, ALL_OBJECT_OPERATIONS),
|
|
endpoint=rpc_endpoint,
|
|
)
|
|
|
|
with reporter.step(f"Check {role} without token has no access to all operations with container"):
|
|
assert_no_access_to_container(test_wallet, container, objects.pop(), file_path, self.shell, self.cluster)
|
|
|
|
with reporter.step(f"Check {role} with token has access to all operations with container"):
|
|
assert_full_access_to_container(test_wallet, container, objects.pop(), file_path, self.shell, self.cluster, bearer)
|
|
|
|
with reporter.step(f"Remove deny rule from APE"):
|
|
frostfs_cli.ape_manager.remove(rpc_endpoint, rule.chain_id, target_name=container, target_type="container")
|
|
|
|
with reporter.step("Wait for one block"):
|
|
self.wait_for_blocks()
|
|
|
|
with reporter.step(f"Check {role} without token has access to all operations with container"):
|
|
assert_full_access_to_container(test_wallet, container, objects.pop(), file_path, self.shell, self.cluster)
|
|
|
|
@allure.title("BearerToken for compound operations (obj_size={object_size})")
|
|
def test_bearer_token_compound_operations(
|
|
self,
|
|
frostfs_cli: FrostfsCli,
|
|
temp_directory: str,
|
|
default_wallet: WalletInfo,
|
|
other_wallet: WalletInfo,
|
|
container: str,
|
|
objects: list[str],
|
|
rpc_endpoint: str,
|
|
file_path: TestFile,
|
|
):
|
|
"""
|
|
Bearer Token COMPLETLY overrides chains set for the specific target.
|
|
Thus, any restictions or permissions should be explicitly defined in BT.
|
|
"""
|
|
|
|
wallets_map = {
|
|
ape.Role.OWNER: default_wallet,
|
|
ape.Role.OTHERS: other_wallet,
|
|
}
|
|
|
|
access_map = {
|
|
ape.Role.OWNER: {
|
|
ape.ObjectOperations.PUT: True,
|
|
ape.ObjectOperations.GET: True,
|
|
ape.ObjectOperations.HEAD: True,
|
|
ape.ObjectOperations.GET_RANGE: True,
|
|
ape.ObjectOperations.GET_RANGE_HASH: True,
|
|
ape.ObjectOperations.SEARCH: True,
|
|
ape.ObjectOperations.DELETE: False,
|
|
},
|
|
ape.Role.OTHERS: {
|
|
ape.ObjectOperations.PUT: True,
|
|
ape.ObjectOperations.GET: True,
|
|
ape.ObjectOperations.HEAD: True,
|
|
ape.ObjectOperations.GET_RANGE: False,
|
|
ape.ObjectOperations.GET_RANGE_HASH: False,
|
|
ape.ObjectOperations.SEARCH: False,
|
|
ape.ObjectOperations.DELETE: True,
|
|
},
|
|
}
|
|
|
|
bt_access_map = {
|
|
ape.Role.OWNER: {
|
|
ape.ObjectOperations.PUT: True,
|
|
ape.ObjectOperations.GET: False,
|
|
ape.ObjectOperations.HEAD: True,
|
|
ape.ObjectOperations.GET_RANGE: True,
|
|
ape.ObjectOperations.GET_RANGE_HASH: False,
|
|
ape.ObjectOperations.SEARCH: False,
|
|
ape.ObjectOperations.DELETE: True,
|
|
},
|
|
# Bearer Token COMPLETLY overrides chains set for the specific target.
|
|
# Thus, any restictions or permissions should be explicitly defined in BT.
|
|
ape.Role.OTHERS: {
|
|
ape.ObjectOperations.PUT: False,
|
|
ape.ObjectOperations.GET: False,
|
|
ape.ObjectOperations.HEAD: False,
|
|
ape.ObjectOperations.GET_RANGE: False,
|
|
ape.ObjectOperations.GET_RANGE_HASH: False,
|
|
ape.ObjectOperations.SEARCH: False,
|
|
ape.ObjectOperations.DELETE: False,
|
|
},
|
|
}
|
|
|
|
# Operations that we will deny for each role via APE
|
|
deny_map = {
|
|
ape.Role.OWNER: [ape.ObjectOperations.DELETE],
|
|
ape.Role.OTHERS: [
|
|
ape.ObjectOperations.SEARCH,
|
|
ape.ObjectOperations.GET_RANGE_HASH,
|
|
ape.ObjectOperations.GET_RANGE,
|
|
],
|
|
}
|
|
|
|
# Operations that we will allow for each role with bearer token
|
|
bearer_map = {
|
|
ape.Role.OWNER: [
|
|
ape.ObjectOperations.PUT,
|
|
ape.ObjectOperations.HEAD,
|
|
ape.ObjectOperations.GET_RANGE,
|
|
# Delete also requires PUT (to make tobstone) and HEAD (to get simple objects header)
|
|
ape.ObjectOperations.DELETE,
|
|
],
|
|
ape.Role.OTHERS: [
|
|
ape.ObjectOperations.GET,
|
|
ape.ObjectOperations.GET_RANGE,
|
|
ape.ObjectOperations.GET_RANGE_HASH,
|
|
],
|
|
}
|
|
|
|
conditions_map = {
|
|
ape.Role.OWNER: ape.Condition.by_role(ape.Role.OWNER),
|
|
ape.Role.OTHERS: ape.Condition.by_role(ape.Role.OTHERS),
|
|
}
|
|
|
|
verb_map = {ape.Role.OWNER: ape.Verb.ALLOW, ape.Role.OTHERS: ape.Verb.DENY}
|
|
|
|
for role, operations in deny_map.items():
|
|
with reporter.step(f"Add APE deny rule for {role}"):
|
|
rule = ape.Rule(ape.Verb.DENY, operations, conditions_map[role])
|
|
frostfs_cli.ape_manager.add(
|
|
rpc_endpoint, rule.chain_id, target_name=container, target_type="container", rule=rule.as_string()
|
|
)
|
|
|
|
with reporter.step("Wait for one block"):
|
|
self.wait_for_blocks()
|
|
|
|
for role, wallet in wallets_map.items():
|
|
with reporter.step(f"Assert access to container without bearer token for {role}"):
|
|
assert_access_to_container(access_map[role], wallet, container, objects.pop(), file_path, self.shell, self.cluster)
|
|
|
|
bearer_tokens = {}
|
|
for role in wallets_map.keys():
|
|
with reporter.step(f"Create bearer token for {role}"):
|
|
rule = ape.Rule(verb_map[role], bearer_map[role], conditions_map[role])
|
|
bt = create_bearer_token(frostfs_cli, temp_directory, container, rule, rpc_endpoint)
|
|
bearer_tokens[role] = bt
|
|
|
|
for role, wallet in wallets_map.items():
|
|
with reporter.step(f"Assert access to container with bearer token for {role}"):
|
|
assert_access_to_container(
|
|
bt_access_map[role], wallet, container, objects.pop(), file_path, self.shell, self.cluster, bearer_tokens[role]
|
|
)
|