Add static session token container tests
Signed-off-by: Vladimir Avdeev <v.avdeev@yadro.com>
This commit is contained in:
parent
455cafa08a
commit
9b0ac8579b
8 changed files with 444 additions and 200 deletions
|
@ -1,7 +1,5 @@
|
||||||
import logging
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from typing import Optional
|
||||||
logger = logging.getLogger("NeoLogger")
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
@ -12,16 +10,16 @@ class ObjectRef:
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class LockObjectInfo(ObjectRef):
|
class LockObjectInfo(ObjectRef):
|
||||||
lifetime: int = None
|
lifetime: Optional[int] = None
|
||||||
expire_at: int = None
|
expire_at: Optional[int] = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class StorageObjectInfo(ObjectRef):
|
class StorageObjectInfo(ObjectRef):
|
||||||
size: str = None
|
size: Optional[int] = None
|
||||||
wallet_file_path: str = None
|
wallet_file_path: Optional[str] = None
|
||||||
file_path: str = None
|
file_path: Optional[str] = None
|
||||||
file_hash: str = None
|
file_hash: Optional[str] = None
|
||||||
attributes: list[dict[str, str]] = None
|
attributes: Optional[list[dict[str, str]]] = None
|
||||||
tombstone: str = None
|
tombstone: Optional[str] = None
|
||||||
locks: list[LockObjectInfo] = None
|
locks: Optional[list[LockObjectInfo]] = None
|
||||||
|
|
|
@ -4,14 +4,14 @@ import logging
|
||||||
import os
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Optional
|
from enum import Enum
|
||||||
|
from typing import Any, Optional
|
||||||
|
|
||||||
import allure
|
import allure
|
||||||
import json_transformers
|
import json_transformers
|
||||||
from common import ASSETS_DIR, NEOFS_CLI_EXEC, NEOFS_ENDPOINT, WALLET_CONFIG
|
from common import ASSETS_DIR, NEOFS_CLI_EXEC, NEOFS_ENDPOINT, WALLET_CONFIG
|
||||||
from data_formatters import get_wallet_public_key
|
from data_formatters import get_wallet_public_key
|
||||||
from json_transformers import encode_for_json
|
from json_transformers import encode_for_json
|
||||||
from neo3 import wallet
|
|
||||||
from neofs_testlib.cli import NeofsCli
|
from neofs_testlib.cli import NeofsCli
|
||||||
from neofs_testlib.shell import Shell
|
from neofs_testlib.shell import Shell
|
||||||
from storage_object_info import StorageObjectInfo
|
from storage_object_info import StorageObjectInfo
|
||||||
|
@ -19,16 +19,6 @@ from wallet import WalletFile
|
||||||
|
|
||||||
logger = logging.getLogger("NeoLogger")
|
logger = logging.getLogger("NeoLogger")
|
||||||
|
|
||||||
PUT_VERB = "PUT"
|
|
||||||
DELETE_VERB = "DELETE"
|
|
||||||
LOCK_VERB = "LOCK"
|
|
||||||
|
|
||||||
GET_VERB = "GET"
|
|
||||||
RANGEHASH_VERB = "RANGEHASH"
|
|
||||||
RANGE_VERB = "RANGE"
|
|
||||||
HEAD_VERB = "HEAD"
|
|
||||||
SEARCH_VERB = "SEARCH"
|
|
||||||
|
|
||||||
UNRELATED_KEY = "unrelated key in the session"
|
UNRELATED_KEY = "unrelated key in the session"
|
||||||
UNRELATED_OBJECT = "unrelated object in the session"
|
UNRELATED_OBJECT = "unrelated object in the session"
|
||||||
UNRELATED_CONTAINER = "unrelated container in the session"
|
UNRELATED_CONTAINER = "unrelated container in the session"
|
||||||
|
@ -36,6 +26,22 @@ WRONG_VERB = "wrong verb of the session"
|
||||||
INVALID_SIGNATURE = "invalid signature of the session data"
|
INVALID_SIGNATURE = "invalid signature of the session data"
|
||||||
|
|
||||||
|
|
||||||
|
class ObjectVerb(Enum):
|
||||||
|
PUT = "PUT"
|
||||||
|
DELETE = "DELETE"
|
||||||
|
GET = "GET"
|
||||||
|
RANGEHASH = "RANGEHASH"
|
||||||
|
RANGE = "RANGE"
|
||||||
|
HEAD = "HEAD"
|
||||||
|
SEARCH = "SEARCH"
|
||||||
|
|
||||||
|
|
||||||
|
class ContainerVerb(Enum):
|
||||||
|
CREATE = "PUT"
|
||||||
|
DELETE = "DELETE"
|
||||||
|
SETEACL = "SETEACL"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Lifetime:
|
class Lifetime:
|
||||||
exp: int = 100000000
|
exp: int = 100000000
|
||||||
|
@ -44,76 +50,20 @@ class Lifetime:
|
||||||
|
|
||||||
|
|
||||||
@allure.step("Generate Session Token")
|
@allure.step("Generate Session Token")
|
||||||
def generate_session_token(owner: str, session_wallet: str, cid: str = "") -> str:
|
def generate_session_token(
|
||||||
"""
|
|
||||||
This function generates session token for ContainerSessionContext
|
|
||||||
and writes it to the file. It is able to prepare session token file
|
|
||||||
for a specific container (<cid>) or for every container (adds
|
|
||||||
"wildcard" field).
|
|
||||||
Args:
|
|
||||||
owner(str): wallet address of container owner
|
|
||||||
session_wallet(str): the path to wallet to which we grant the
|
|
||||||
access via session token
|
|
||||||
cid(optional, str): container ID of the container; if absent,
|
|
||||||
we assume the session token is generated for any
|
|
||||||
container
|
|
||||||
Returns:
|
|
||||||
(str): the path to the generated session token file
|
|
||||||
"""
|
|
||||||
file_path = os.path.join(os.getcwd(), ASSETS_DIR, str(uuid.uuid4()))
|
|
||||||
|
|
||||||
session_wlt_content = ""
|
|
||||||
with open(session_wallet) as fout:
|
|
||||||
session_wlt_content = json.load(fout)
|
|
||||||
session_wlt = wallet.Wallet.from_json(session_wlt_content, password="")
|
|
||||||
pub_key_64 = base64.b64encode(bytes.fromhex(str(session_wlt.accounts[0].public_key))).decode(
|
|
||||||
"utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
session_token = {
|
|
||||||
"body": {
|
|
||||||
"id": f"{base64.b64encode(uuid.uuid4().bytes).decode('utf-8')}",
|
|
||||||
"ownerID": {"value": f"{json_transformers.encode_for_json(owner)}"},
|
|
||||||
"lifetime": {"exp": "100000000", "nbf": "0", "iat": "0"},
|
|
||||||
"sessionKey": f"{pub_key_64}",
|
|
||||||
"container": {
|
|
||||||
"verb": "PUT",
|
|
||||||
"wildcard": cid != "",
|
|
||||||
**({"containerID": {"value": f"{encode_for_json(cid)}"}} if cid != "" else {}),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info(f"Got this Session Token: {session_token}")
|
|
||||||
with open(file_path, "w", encoding="utf-8") as session_token_file:
|
|
||||||
json.dump(session_token, session_token_file, ensure_ascii=False, indent=4)
|
|
||||||
|
|
||||||
return file_path
|
|
||||||
|
|
||||||
|
|
||||||
@allure.step("Generate Session Token For Object")
|
|
||||||
def generate_object_session_token(
|
|
||||||
owner_wallet: WalletFile,
|
owner_wallet: WalletFile,
|
||||||
session_wallet: WalletFile,
|
session_wallet: WalletFile,
|
||||||
oids: list[str],
|
session: dict[str, dict[str, Any]],
|
||||||
cid: str,
|
|
||||||
verb: str,
|
|
||||||
tokens_dir: str,
|
tokens_dir: str,
|
||||||
lifetime: Optional[Lifetime] = None,
|
lifetime: Optional[Lifetime] = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
This function generates session token for ObjectSessionContext
|
This function generates session token and writes it to the file.
|
||||||
and writes it to the file. It is able to prepare session token file
|
|
||||||
for a specific container (<cid>) or for every container (adds
|
|
||||||
"wildcard" field).
|
|
||||||
Args:
|
Args:
|
||||||
owner_wallet: wallet of container owner
|
owner_wallet: wallet of container owner
|
||||||
session_wallet: wallet to which we grant the
|
session_wallet: wallet to which we grant the access via session token
|
||||||
access via session token
|
session: Contains allowed operation with parameters
|
||||||
cid: container ID of the container
|
tokens_dir: Dir for token
|
||||||
oids: list of objectIDs to put into session
|
|
||||||
verb: verb to grant access to;
|
|
||||||
Valid verbs are: GET, RANGE, RANGEHASH, HEAD, SEARCH.
|
|
||||||
lifetime: lifetime options for session
|
lifetime: lifetime options for session
|
||||||
Returns:
|
Returns:
|
||||||
The path to the generated session token file
|
The path to the generated session token file
|
||||||
|
@ -123,7 +73,7 @@ def generate_object_session_token(
|
||||||
|
|
||||||
pub_key_64 = get_wallet_public_key(session_wallet.path, session_wallet.password, "base64")
|
pub_key_64 = get_wallet_public_key(session_wallet.path, session_wallet.password, "base64")
|
||||||
|
|
||||||
lifetime = lifetime if lifetime else Lifetime()
|
lifetime = lifetime or Lifetime()
|
||||||
|
|
||||||
session_token = {
|
session_token = {
|
||||||
"body": {
|
"body": {
|
||||||
|
@ -137,15 +87,9 @@ def generate_object_session_token(
|
||||||
"iat": f"{lifetime.iat}",
|
"iat": f"{lifetime.iat}",
|
||||||
},
|
},
|
||||||
"sessionKey": pub_key_64,
|
"sessionKey": pub_key_64,
|
||||||
"object": {
|
|
||||||
"verb": verb,
|
|
||||||
"target": {
|
|
||||||
"container": {"value": encode_for_json(cid)},
|
|
||||||
"objects": [{"value": encode_for_json(oid)} for oid in oids],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
session_token["body"].update(session)
|
||||||
|
|
||||||
logger.info(f"Got this Session Token: {session_token}")
|
logger.info(f"Got this Session Token: {session_token}")
|
||||||
with open(file_path, "w", encoding="utf-8") as session_token_file:
|
with open(file_path, "w", encoding="utf-8") as session_token_file:
|
||||||
|
@ -154,12 +98,117 @@ def generate_object_session_token(
|
||||||
return file_path
|
return file_path
|
||||||
|
|
||||||
|
|
||||||
|
@allure.step("Generate Session Token For Container")
|
||||||
|
def generate_container_session_token(
|
||||||
|
owner_wallet: WalletFile,
|
||||||
|
session_wallet: WalletFile,
|
||||||
|
verb: ContainerVerb,
|
||||||
|
tokens_dir: str,
|
||||||
|
lifetime: Optional[Lifetime] = None,
|
||||||
|
cid: Optional[str] = None,
|
||||||
|
) -> str:
|
||||||
|
"""
|
||||||
|
This function generates session token for ContainerSessionContext
|
||||||
|
and writes it to the file. It is able to prepare session token file
|
||||||
|
for a specific container (<cid>) or for every container (adds
|
||||||
|
"wildcard" field).
|
||||||
|
Args:
|
||||||
|
owner_wallet: wallet of container owner.
|
||||||
|
session_wallet: wallet to which we grant the access via session token.
|
||||||
|
verb: verb to grant access to.
|
||||||
|
lifetime: lifetime options for session.
|
||||||
|
cid: container ID of the container
|
||||||
|
Returns:
|
||||||
|
The path to the generated session token file
|
||||||
|
"""
|
||||||
|
session = {
|
||||||
|
"container": {
|
||||||
|
"verb": verb.value,
|
||||||
|
"wildcard": cid is not None,
|
||||||
|
**({"containerID": {"value": f"{encode_for_json(cid)}"}} if cid is not None else {}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return generate_session_token(
|
||||||
|
owner_wallet=owner_wallet,
|
||||||
|
session_wallet=session_wallet,
|
||||||
|
session=session,
|
||||||
|
tokens_dir=tokens_dir,
|
||||||
|
lifetime=lifetime,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@allure.step("Generate Session Token For Object")
|
||||||
|
def generate_object_session_token(
|
||||||
|
owner_wallet: WalletFile,
|
||||||
|
session_wallet: WalletFile,
|
||||||
|
oids: list[str],
|
||||||
|
cid: str,
|
||||||
|
verb: ObjectVerb,
|
||||||
|
tokens_dir: str,
|
||||||
|
lifetime: Optional[Lifetime] = None,
|
||||||
|
) -> str:
|
||||||
|
"""
|
||||||
|
This function generates session token for ObjectSessionContext
|
||||||
|
and writes it to the file.
|
||||||
|
Args:
|
||||||
|
owner_wallet: wallet of container owner
|
||||||
|
session_wallet: wallet to which we grant the access via session token
|
||||||
|
cid: container ID of the container
|
||||||
|
oids: list of objectIDs to put into session
|
||||||
|
verb: verb to grant access to; Valid verbs are: ObjectVerb.
|
||||||
|
lifetime: lifetime options for session
|
||||||
|
Returns:
|
||||||
|
The path to the generated session token file
|
||||||
|
"""
|
||||||
|
session = {
|
||||||
|
"object": {
|
||||||
|
"verb": verb.value,
|
||||||
|
"target": {
|
||||||
|
"container": {"value": encode_for_json(cid)},
|
||||||
|
"objects": [{"value": encode_for_json(oid)} for oid in oids],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return generate_session_token(
|
||||||
|
owner_wallet=owner_wallet,
|
||||||
|
session_wallet=session_wallet,
|
||||||
|
session=session,
|
||||||
|
tokens_dir=tokens_dir,
|
||||||
|
lifetime=lifetime,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@allure.step("Get signed token for object session")
|
||||||
|
def get_container_signed_token(
|
||||||
|
owner_wallet: WalletFile,
|
||||||
|
user_wallet: WalletFile,
|
||||||
|
verb: ContainerVerb,
|
||||||
|
shell: Shell,
|
||||||
|
tokens_dir: str,
|
||||||
|
lifetime: Optional[Lifetime] = None,
|
||||||
|
) -> str:
|
||||||
|
"""
|
||||||
|
Returns signed token file path for static object session
|
||||||
|
"""
|
||||||
|
session_token_file = generate_container_session_token(
|
||||||
|
owner_wallet=owner_wallet,
|
||||||
|
session_wallet=user_wallet,
|
||||||
|
verb=verb,
|
||||||
|
tokens_dir=tokens_dir,
|
||||||
|
lifetime=lifetime,
|
||||||
|
)
|
||||||
|
return sign_session_token(shell, session_token_file, owner_wallet)
|
||||||
|
|
||||||
|
|
||||||
@allure.step("Get signed token for object session")
|
@allure.step("Get signed token for object session")
|
||||||
def get_object_signed_token(
|
def get_object_signed_token(
|
||||||
owner_wallet: WalletFile,
|
owner_wallet: WalletFile,
|
||||||
user_wallet: WalletFile,
|
user_wallet: WalletFile,
|
||||||
|
cid: str,
|
||||||
storage_objects: list[StorageObjectInfo],
|
storage_objects: list[StorageObjectInfo],
|
||||||
verb: str,
|
verb: ObjectVerb,
|
||||||
shell: Shell,
|
shell: Shell,
|
||||||
tokens_dir: str,
|
tokens_dir: str,
|
||||||
lifetime: Optional[Lifetime] = None,
|
lifetime: Optional[Lifetime] = None,
|
||||||
|
@ -169,15 +218,15 @@ def get_object_signed_token(
|
||||||
"""
|
"""
|
||||||
storage_object_ids = [storage_object.oid for storage_object in storage_objects]
|
storage_object_ids = [storage_object.oid for storage_object in storage_objects]
|
||||||
session_token_file = generate_object_session_token(
|
session_token_file = generate_object_session_token(
|
||||||
owner_wallet,
|
owner_wallet=owner_wallet,
|
||||||
user_wallet,
|
session_wallet=user_wallet,
|
||||||
storage_object_ids,
|
oids=storage_object_ids,
|
||||||
owner_wallet.containers[0],
|
cid=cid,
|
||||||
verb,
|
verb=verb,
|
||||||
tokens_dir,
|
tokens_dir=tokens_dir,
|
||||||
lifetime=lifetime,
|
lifetime=lifetime,
|
||||||
)
|
)
|
||||||
return sign_session_token(shell, session_token_file, owner_wallet.path)
|
return sign_session_token(shell, session_token_file, owner_wallet)
|
||||||
|
|
||||||
|
|
||||||
@allure.step("Create Session Token")
|
@allure.step("Create Session Token")
|
||||||
|
@ -212,7 +261,7 @@ def create_session_token(
|
||||||
|
|
||||||
|
|
||||||
@allure.step("Sign Session Token")
|
@allure.step("Sign Session Token")
|
||||||
def sign_session_token(shell: Shell, session_token_file: str, wlt: str) -> str:
|
def sign_session_token(shell: Shell, session_token_file: str, wlt: WalletFile) -> str:
|
||||||
"""
|
"""
|
||||||
This function signs the session token by the given wallet.
|
This function signs the session token by the given wallet.
|
||||||
|
|
||||||
|
@ -227,6 +276,6 @@ def sign_session_token(shell: Shell, session_token_file: str, wlt: str) -> str:
|
||||||
signed_token_file = os.path.join(os.getcwd(), ASSETS_DIR, str(uuid.uuid4()))
|
signed_token_file = os.path.join(os.getcwd(), ASSETS_DIR, str(uuid.uuid4()))
|
||||||
neofscli = NeofsCli(shell=shell, neofs_cli_exec_path=NEOFS_CLI_EXEC, config_file=WALLET_CONFIG)
|
neofscli = NeofsCli(shell=shell, neofs_cli_exec_path=NEOFS_CLI_EXEC, config_file=WALLET_CONFIG)
|
||||||
neofscli.util.sign_session_token(
|
neofscli.util.sign_session_token(
|
||||||
wallet=wlt, from_file=session_token_file, to_file=signed_token_file
|
wallet=wlt.path, from_file=session_token_file, to_file=signed_token_file
|
||||||
)
|
)
|
||||||
return signed_token_file
|
return signed_token_file
|
||||||
|
|
26
pytest_tests/testsuites/session_token/conftest.py
Normal file
26
pytest_tests/testsuites/session_token/conftest.py
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import pytest
|
||||||
|
from wallet import WalletFactory, WalletFile
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def owner_wallet(wallet_factory: WalletFactory) -> WalletFile:
|
||||||
|
"""
|
||||||
|
Returns wallet which owns containers and objects
|
||||||
|
"""
|
||||||
|
return wallet_factory.create_wallet()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def user_wallet(wallet_factory: WalletFactory) -> WalletFile:
|
||||||
|
"""
|
||||||
|
Returns wallet which will use objects from owner via static session
|
||||||
|
"""
|
||||||
|
return wallet_factory.create_wallet()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def stranger_wallet(wallet_factory: WalletFactory) -> WalletFile:
|
||||||
|
"""
|
||||||
|
Returns stranger wallet which should fail to obtain data
|
||||||
|
"""
|
||||||
|
return wallet_factory.create_wallet()
|
|
@ -6,7 +6,6 @@ from common import COMPLEX_OBJ_SIZE, SIMPLE_OBJ_SIZE
|
||||||
from epoch import ensure_fresh_epoch, tick_epoch
|
from epoch import ensure_fresh_epoch, tick_epoch
|
||||||
from file_helper import generate_file
|
from file_helper import generate_file
|
||||||
from grpc_responses import MALFORMED_REQUEST, OBJECT_ACCESS_DENIED, OBJECT_NOT_FOUND
|
from grpc_responses import MALFORMED_REQUEST, OBJECT_ACCESS_DENIED, OBJECT_NOT_FOUND
|
||||||
from neofs_testlib.hosting import Hosting
|
|
||||||
from neofs_testlib.shell import Shell
|
from neofs_testlib.shell import Shell
|
||||||
from pytest import FixtureRequest
|
from pytest import FixtureRequest
|
||||||
from python_keywords.container import create_container
|
from python_keywords.container import create_container
|
||||||
|
@ -20,23 +19,17 @@ from python_keywords.neofs_verbs import (
|
||||||
put_object,
|
put_object,
|
||||||
search_object,
|
search_object,
|
||||||
)
|
)
|
||||||
from wallet import WalletFactory, WalletFile
|
from wallet import WalletFile
|
||||||
|
|
||||||
from helpers.storage_object_info import StorageObjectInfo
|
from helpers.storage_object_info import StorageObjectInfo
|
||||||
from steps.session_token import (
|
from steps.session_token import (
|
||||||
DELETE_VERB,
|
|
||||||
GET_VERB,
|
|
||||||
HEAD_VERB,
|
|
||||||
INVALID_SIGNATURE,
|
INVALID_SIGNATURE,
|
||||||
PUT_VERB,
|
|
||||||
RANGE_VERB,
|
|
||||||
RANGEHASH_VERB,
|
|
||||||
SEARCH_VERB,
|
|
||||||
UNRELATED_CONTAINER,
|
UNRELATED_CONTAINER,
|
||||||
UNRELATED_KEY,
|
UNRELATED_KEY,
|
||||||
UNRELATED_OBJECT,
|
UNRELATED_OBJECT,
|
||||||
WRONG_VERB,
|
WRONG_VERB,
|
||||||
Lifetime,
|
Lifetime,
|
||||||
|
ObjectVerb,
|
||||||
generate_object_session_token,
|
generate_object_session_token,
|
||||||
get_object_signed_token,
|
get_object_signed_token,
|
||||||
sign_session_token,
|
sign_session_token,
|
||||||
|
@ -48,6 +41,14 @@ logger = logging.getLogger("NeoLogger")
|
||||||
RANGE_OFFSET_FOR_COMPLEX_OBJECT = 200
|
RANGE_OFFSET_FOR_COMPLEX_OBJECT = 200
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def storage_containers(owner_wallet: WalletFile, client_shell: Shell) -> list[str]:
|
||||||
|
# Separate containers for complex/simple objects to avoid side-effects
|
||||||
|
cid = create_container(owner_wallet.path, shell=client_shell)
|
||||||
|
other_cid = create_container(owner_wallet.path, shell=client_shell)
|
||||||
|
yield [cid, other_cid]
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(
|
@pytest.fixture(
|
||||||
params=[SIMPLE_OBJ_SIZE, COMPLEX_OBJ_SIZE],
|
params=[SIMPLE_OBJ_SIZE, COMPLEX_OBJ_SIZE],
|
||||||
ids=["simple object", "complex object"],
|
ids=["simple object", "complex object"],
|
||||||
|
@ -55,27 +56,26 @@ RANGE_OFFSET_FOR_COMPLEX_OBJECT = 200
|
||||||
scope="module",
|
scope="module",
|
||||||
)
|
)
|
||||||
def storage_objects(
|
def storage_objects(
|
||||||
owner_wallet: WalletFile, client_shell: Shell, request: FixtureRequest
|
owner_wallet: WalletFile,
|
||||||
|
client_shell: Shell,
|
||||||
|
storage_containers: list[str],
|
||||||
|
request: FixtureRequest,
|
||||||
) -> list[StorageObjectInfo]:
|
) -> list[StorageObjectInfo]:
|
||||||
|
|
||||||
file_path = generate_file(request.param)
|
file_path = generate_file(request.param)
|
||||||
storage_objects = []
|
storage_objects = []
|
||||||
|
|
||||||
# Separate containers for complex/simple objects to avoid side-effects
|
|
||||||
cid = create_container(owner_wallet.path, shell=client_shell)
|
|
||||||
other_cid = create_container(owner_wallet.path, shell=client_shell)
|
|
||||||
owner_wallet.containers = [cid, other_cid]
|
|
||||||
|
|
||||||
with allure.step("Put objects"):
|
with allure.step("Put objects"):
|
||||||
# upload couple objects
|
# upload couple objects
|
||||||
for _ in range(3):
|
for _ in range(3):
|
||||||
storage_object_id = put_object(
|
storage_object_id = put_object(
|
||||||
wallet=owner_wallet.path,
|
wallet=owner_wallet.path,
|
||||||
path=file_path,
|
path=file_path,
|
||||||
cid=cid,
|
cid=storage_containers[0],
|
||||||
shell=client_shell,
|
shell=client_shell,
|
||||||
)
|
)
|
||||||
|
|
||||||
storage_object = StorageObjectInfo(cid, storage_object_id)
|
storage_object = StorageObjectInfo(storage_containers[0], storage_object_id)
|
||||||
storage_object.size = request.param
|
storage_object.size = request.param
|
||||||
storage_object.wallet_file_path = owner_wallet.path
|
storage_object.wallet_file_path = owner_wallet.path
|
||||||
storage_object.file_path = file_path
|
storage_object.file_path = file_path
|
||||||
|
@ -102,56 +102,38 @@ def get_ranges(storage_object: StorageObjectInfo, shell: Shell) -> list[str]:
|
||||||
return [
|
return [
|
||||||
"0:10",
|
"0:10",
|
||||||
f"{object_size-10}:10",
|
f"{object_size-10}:10",
|
||||||
f"{max_object_size - RANGE_OFFSET_FOR_COMPLEX_OBJECT}:{RANGE_OFFSET_FOR_COMPLEX_OBJECT * 2}",
|
f"{max_object_size - RANGE_OFFSET_FOR_COMPLEX_OBJECT}:"
|
||||||
|
f"{RANGE_OFFSET_FOR_COMPLEX_OBJECT * 2}",
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
return ["0:10", f"{object_size-10}:10"]
|
return ["0:10", f"{object_size-10}:10"]
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
|
||||||
def owner_wallet(wallet_factory: WalletFactory) -> WalletFile:
|
|
||||||
"""
|
|
||||||
Returns wallet which owns containers and objects
|
|
||||||
"""
|
|
||||||
return wallet_factory.create_wallet()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
|
||||||
def user_wallet(wallet_factory: WalletFactory) -> WalletFile:
|
|
||||||
"""
|
|
||||||
Returns wallet which will use objects from owner via static session
|
|
||||||
"""
|
|
||||||
return wallet_factory.create_wallet()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
|
||||||
def stranger_wallet(wallet_factory: WalletFactory) -> WalletFile:
|
|
||||||
"""
|
|
||||||
Returns stranger wallet which should fail to obtain data
|
|
||||||
"""
|
|
||||||
return wallet_factory.create_wallet()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def static_sessions(
|
def static_sessions(
|
||||||
owner_wallet: WalletFile,
|
owner_wallet: WalletFile,
|
||||||
user_wallet: WalletFile,
|
user_wallet: WalletFile,
|
||||||
|
storage_containers: list[str],
|
||||||
storage_objects: list[StorageObjectInfo],
|
storage_objects: list[StorageObjectInfo],
|
||||||
client_shell: Shell,
|
client_shell: Shell,
|
||||||
prepare_tmp_dir: str,
|
prepare_tmp_dir: str,
|
||||||
) -> dict[str, str]:
|
) -> dict[ObjectVerb, str]:
|
||||||
"""
|
"""
|
||||||
Returns dict with static session token file paths for all verbs with default lifetime with valid container and first two objects
|
Returns dict with static session token file paths for all verbs with default lifetime with
|
||||||
|
valid container and first two objects
|
||||||
"""
|
"""
|
||||||
verbs = [GET_VERB, RANGEHASH_VERB, RANGE_VERB, HEAD_VERB, SEARCH_VERB, DELETE_VERB, PUT_VERB]
|
return {
|
||||||
sessions = {}
|
verb: get_object_signed_token(
|
||||||
|
owner_wallet,
|
||||||
for verb in verbs:
|
user_wallet,
|
||||||
sessions[verb] = get_object_signed_token(
|
storage_containers[0],
|
||||||
owner_wallet, user_wallet, storage_objects[0:2], verb, client_shell, prepare_tmp_dir
|
storage_objects[0:2],
|
||||||
|
verb,
|
||||||
|
client_shell,
|
||||||
|
prepare_tmp_dir,
|
||||||
)
|
)
|
||||||
|
for verb in ObjectVerb
|
||||||
return sessions
|
}
|
||||||
|
|
||||||
|
|
||||||
@allure.title("Validate static session with read operations")
|
@allure.title("Validate static session with read operations")
|
||||||
|
@ -159,17 +141,17 @@ def static_sessions(
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"method_under_test,verb",
|
"method_under_test,verb",
|
||||||
[
|
[
|
||||||
(head_object, HEAD_VERB),
|
(head_object, ObjectVerb.HEAD),
|
||||||
(get_object, GET_VERB),
|
(get_object, ObjectVerb.GET),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_static_session_read(
|
def test_static_session_read(
|
||||||
user_wallet: WalletFile,
|
user_wallet: WalletFile,
|
||||||
client_shell: Shell,
|
client_shell: Shell,
|
||||||
storage_objects: list[StorageObjectInfo],
|
storage_objects: list[StorageObjectInfo],
|
||||||
static_sessions: list[str],
|
static_sessions: dict[ObjectVerb, str],
|
||||||
method_under_test,
|
method_under_test,
|
||||||
verb: str,
|
verb: ObjectVerb,
|
||||||
request: FixtureRequest,
|
request: FixtureRequest,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
@ -193,15 +175,15 @@ def test_static_session_read(
|
||||||
@pytest.mark.static_session
|
@pytest.mark.static_session
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"method_under_test,verb",
|
"method_under_test,verb",
|
||||||
[(get_range, RANGE_VERB), (get_range_hash, RANGEHASH_VERB)],
|
[(get_range, ObjectVerb.RANGE), (get_range_hash, ObjectVerb.RANGEHASH)],
|
||||||
)
|
)
|
||||||
def test_static_session_range(
|
def test_static_session_range(
|
||||||
user_wallet: WalletFile,
|
user_wallet: WalletFile,
|
||||||
client_shell: Shell,
|
client_shell: Shell,
|
||||||
storage_objects: list[StorageObjectInfo],
|
storage_objects: list[StorageObjectInfo],
|
||||||
static_sessions: list[str],
|
static_sessions: dict[ObjectVerb, str],
|
||||||
method_under_test,
|
method_under_test,
|
||||||
verb: str,
|
verb: ObjectVerb,
|
||||||
request: FixtureRequest,
|
request: FixtureRequest,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
@ -233,7 +215,7 @@ def test_static_session_search(
|
||||||
user_wallet: WalletFile,
|
user_wallet: WalletFile,
|
||||||
client_shell: Shell,
|
client_shell: Shell,
|
||||||
storage_objects: list[StorageObjectInfo],
|
storage_objects: list[StorageObjectInfo],
|
||||||
static_sessions: list[str],
|
static_sessions: dict[ObjectVerb, str],
|
||||||
request: FixtureRequest,
|
request: FixtureRequest,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
@ -244,7 +226,7 @@ def test_static_session_search(
|
||||||
cid = storage_objects[0].cid
|
cid = storage_objects[0].cid
|
||||||
expected_object_ids = [storage_object.oid for storage_object in storage_objects[0:2]]
|
expected_object_ids = [storage_object.oid for storage_object in storage_objects[0:2]]
|
||||||
actual_object_ids = search_object(
|
actual_object_ids = search_object(
|
||||||
user_wallet.path, cid, client_shell, session=static_sessions[SEARCH_VERB], root=True
|
user_wallet.path, cid, client_shell, session=static_sessions[ObjectVerb.SEARCH], root=True
|
||||||
)
|
)
|
||||||
assert expected_object_ids == actual_object_ids
|
assert expected_object_ids == actual_object_ids
|
||||||
|
|
||||||
|
@ -255,7 +237,7 @@ def test_static_session_unrelated_object(
|
||||||
user_wallet: WalletFile,
|
user_wallet: WalletFile,
|
||||||
client_shell: Shell,
|
client_shell: Shell,
|
||||||
storage_objects: list[StorageObjectInfo],
|
storage_objects: list[StorageObjectInfo],
|
||||||
static_sessions: list[str],
|
static_sessions: dict[ObjectVerb, str],
|
||||||
request: FixtureRequest,
|
request: FixtureRequest,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
@ -270,7 +252,7 @@ def test_static_session_unrelated_object(
|
||||||
storage_objects[2].cid,
|
storage_objects[2].cid,
|
||||||
storage_objects[2].oid,
|
storage_objects[2].oid,
|
||||||
client_shell,
|
client_shell,
|
||||||
session=static_sessions[HEAD_VERB],
|
session=static_sessions[ObjectVerb.HEAD],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -280,7 +262,7 @@ def test_static_session_head_unrelated_user(
|
||||||
stranger_wallet: WalletFile,
|
stranger_wallet: WalletFile,
|
||||||
client_shell: Shell,
|
client_shell: Shell,
|
||||||
storage_objects: list[StorageObjectInfo],
|
storage_objects: list[StorageObjectInfo],
|
||||||
static_sessions: list[str],
|
static_sessions: dict[ObjectVerb, str],
|
||||||
request: FixtureRequest,
|
request: FixtureRequest,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
@ -297,7 +279,7 @@ def test_static_session_head_unrelated_user(
|
||||||
storage_object.cid,
|
storage_object.cid,
|
||||||
storage_object.oid,
|
storage_object.oid,
|
||||||
client_shell,
|
client_shell,
|
||||||
session=static_sessions[HEAD_VERB],
|
session=static_sessions[ObjectVerb.HEAD],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -307,7 +289,7 @@ def test_static_session_head_wrong_verb(
|
||||||
user_wallet: WalletFile,
|
user_wallet: WalletFile,
|
||||||
client_shell: Shell,
|
client_shell: Shell,
|
||||||
storage_objects: list[StorageObjectInfo],
|
storage_objects: list[StorageObjectInfo],
|
||||||
static_sessions: list[str],
|
static_sessions: dict[ObjectVerb, str],
|
||||||
request: FixtureRequest,
|
request: FixtureRequest,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
@ -324,7 +306,7 @@ def test_static_session_head_wrong_verb(
|
||||||
storage_object.cid,
|
storage_object.cid,
|
||||||
storage_object.oid,
|
storage_object.oid,
|
||||||
client_shell,
|
client_shell,
|
||||||
session=static_sessions[HEAD_VERB],
|
session=static_sessions[ObjectVerb.HEAD],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -334,8 +316,9 @@ def test_static_session_unrelated_container(
|
||||||
owner_wallet: WalletFile,
|
owner_wallet: WalletFile,
|
||||||
user_wallet: WalletFile,
|
user_wallet: WalletFile,
|
||||||
client_shell: Shell,
|
client_shell: Shell,
|
||||||
|
storage_containers: list[str],
|
||||||
storage_objects: list[StorageObjectInfo],
|
storage_objects: list[StorageObjectInfo],
|
||||||
static_sessions: list[str],
|
static_sessions: dict[ObjectVerb, str],
|
||||||
request: FixtureRequest,
|
request: FixtureRequest,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
@ -349,10 +332,10 @@ def test_static_session_unrelated_container(
|
||||||
with pytest.raises(Exception, match=UNRELATED_CONTAINER):
|
with pytest.raises(Exception, match=UNRELATED_CONTAINER):
|
||||||
get_object(
|
get_object(
|
||||||
user_wallet.path,
|
user_wallet.path,
|
||||||
owner_wallet.containers[1],
|
storage_containers[1],
|
||||||
storage_object.oid,
|
storage_object.oid,
|
||||||
client_shell,
|
client_shell,
|
||||||
session=static_sessions[GET_VERB],
|
session=static_sessions[ObjectVerb.GET],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -363,6 +346,7 @@ def test_static_session_signed_by_other(
|
||||||
user_wallet: WalletFile,
|
user_wallet: WalletFile,
|
||||||
stranger_wallet: WalletFile,
|
stranger_wallet: WalletFile,
|
||||||
client_shell: Shell,
|
client_shell: Shell,
|
||||||
|
storage_containers: list[str],
|
||||||
storage_objects: list[StorageObjectInfo],
|
storage_objects: list[StorageObjectInfo],
|
||||||
prepare_tmp_dir: str,
|
prepare_tmp_dir: str,
|
||||||
request: FixtureRequest,
|
request: FixtureRequest,
|
||||||
|
@ -379,11 +363,11 @@ def test_static_session_signed_by_other(
|
||||||
owner_wallet,
|
owner_wallet,
|
||||||
user_wallet,
|
user_wallet,
|
||||||
[storage_object.oid],
|
[storage_object.oid],
|
||||||
owner_wallet.containers[0],
|
storage_containers[0],
|
||||||
HEAD_VERB,
|
ObjectVerb.HEAD,
|
||||||
prepare_tmp_dir,
|
prepare_tmp_dir,
|
||||||
)
|
)
|
||||||
signed_token_file = sign_session_token(client_shell, session_token_file, stranger_wallet.path)
|
signed_token_file = sign_session_token(client_shell, session_token_file, stranger_wallet)
|
||||||
with pytest.raises(Exception, match=OBJECT_ACCESS_DENIED):
|
with pytest.raises(Exception, match=OBJECT_ACCESS_DENIED):
|
||||||
head_object(
|
head_object(
|
||||||
user_wallet.path,
|
user_wallet.path,
|
||||||
|
@ -400,6 +384,7 @@ def test_static_session_signed_for_other_container(
|
||||||
owner_wallet: WalletFile,
|
owner_wallet: WalletFile,
|
||||||
user_wallet: WalletFile,
|
user_wallet: WalletFile,
|
||||||
client_shell: Shell,
|
client_shell: Shell,
|
||||||
|
storage_containers: list[str],
|
||||||
storage_objects: list[StorageObjectInfo],
|
storage_objects: list[StorageObjectInfo],
|
||||||
prepare_tmp_dir: str,
|
prepare_tmp_dir: str,
|
||||||
request: FixtureRequest,
|
request: FixtureRequest,
|
||||||
|
@ -411,12 +396,12 @@ def test_static_session_signed_for_other_container(
|
||||||
f"Validate static session which signed for another container for {request.node.callspec.id}"
|
f"Validate static session which signed for another container for {request.node.callspec.id}"
|
||||||
)
|
)
|
||||||
storage_object = storage_objects[0]
|
storage_object = storage_objects[0]
|
||||||
container = owner_wallet.containers[1]
|
container = storage_containers[1]
|
||||||
|
|
||||||
session_token_file = generate_object_session_token(
|
session_token_file = generate_object_session_token(
|
||||||
owner_wallet, user_wallet, [storage_object.oid], container, HEAD_VERB, prepare_tmp_dir
|
owner_wallet, user_wallet, [storage_object.oid], container, ObjectVerb.HEAD, prepare_tmp_dir
|
||||||
)
|
)
|
||||||
signed_token_file = sign_session_token(client_shell, session_token_file, owner_wallet.path)
|
signed_token_file = sign_session_token(client_shell, session_token_file, owner_wallet)
|
||||||
with pytest.raises(Exception, match=OBJECT_NOT_FOUND):
|
with pytest.raises(Exception, match=OBJECT_NOT_FOUND):
|
||||||
head_object(
|
head_object(
|
||||||
user_wallet.path, container, storage_object.oid, client_shell, session=signed_token_file
|
user_wallet.path, container, storage_object.oid, client_shell, session=signed_token_file
|
||||||
|
@ -429,6 +414,7 @@ def test_static_session_without_sign(
|
||||||
owner_wallet: WalletFile,
|
owner_wallet: WalletFile,
|
||||||
user_wallet: WalletFile,
|
user_wallet: WalletFile,
|
||||||
client_shell: Shell,
|
client_shell: Shell,
|
||||||
|
storage_containers: list[str],
|
||||||
storage_objects: list[StorageObjectInfo],
|
storage_objects: list[StorageObjectInfo],
|
||||||
prepare_tmp_dir: str,
|
prepare_tmp_dir: str,
|
||||||
request: FixtureRequest,
|
request: FixtureRequest,
|
||||||
|
@ -445,8 +431,8 @@ def test_static_session_without_sign(
|
||||||
owner_wallet,
|
owner_wallet,
|
||||||
user_wallet,
|
user_wallet,
|
||||||
[storage_object.oid],
|
[storage_object.oid],
|
||||||
owner_wallet.containers[0],
|
storage_containers[0],
|
||||||
HEAD_VERB,
|
ObjectVerb.HEAD,
|
||||||
prepare_tmp_dir,
|
prepare_tmp_dir,
|
||||||
)
|
)
|
||||||
with pytest.raises(Exception, match=INVALID_SIGNATURE):
|
with pytest.raises(Exception, match=INVALID_SIGNATURE):
|
||||||
|
@ -465,6 +451,7 @@ def test_static_session_expiration_at_next(
|
||||||
owner_wallet: WalletFile,
|
owner_wallet: WalletFile,
|
||||||
user_wallet: WalletFile,
|
user_wallet: WalletFile,
|
||||||
client_shell: Shell,
|
client_shell: Shell,
|
||||||
|
storage_containers: list[str],
|
||||||
storage_objects: list[StorageObjectInfo],
|
storage_objects: list[StorageObjectInfo],
|
||||||
prepare_tmp_dir: str,
|
prepare_tmp_dir: str,
|
||||||
request: FixtureRequest,
|
request: FixtureRequest,
|
||||||
|
@ -477,15 +464,16 @@ def test_static_session_expiration_at_next(
|
||||||
)
|
)
|
||||||
epoch = ensure_fresh_epoch(client_shell)
|
epoch = ensure_fresh_epoch(client_shell)
|
||||||
|
|
||||||
container = owner_wallet.containers[0]
|
container = storage_containers[0]
|
||||||
object_id = storage_objects[0].oid
|
object_id = storage_objects[0].oid
|
||||||
expiration = Lifetime(epoch + 1, epoch, epoch)
|
expiration = Lifetime(epoch + 1, epoch, epoch)
|
||||||
|
|
||||||
token_expire_at_next_epoch = get_object_signed_token(
|
token_expire_at_next_epoch = get_object_signed_token(
|
||||||
owner_wallet,
|
owner_wallet,
|
||||||
user_wallet,
|
user_wallet,
|
||||||
|
container,
|
||||||
storage_objects,
|
storage_objects,
|
||||||
HEAD_VERB,
|
ObjectVerb.HEAD,
|
||||||
client_shell,
|
client_shell,
|
||||||
prepare_tmp_dir,
|
prepare_tmp_dir,
|
||||||
expiration,
|
expiration,
|
||||||
|
@ -509,6 +497,7 @@ def test_static_session_start_at_next(
|
||||||
owner_wallet: WalletFile,
|
owner_wallet: WalletFile,
|
||||||
user_wallet: WalletFile,
|
user_wallet: WalletFile,
|
||||||
client_shell: Shell,
|
client_shell: Shell,
|
||||||
|
storage_containers: list[str],
|
||||||
storage_objects: list[StorageObjectInfo],
|
storage_objects: list[StorageObjectInfo],
|
||||||
prepare_tmp_dir: str,
|
prepare_tmp_dir: str,
|
||||||
request: FixtureRequest,
|
request: FixtureRequest,
|
||||||
|
@ -517,19 +506,21 @@ def test_static_session_start_at_next(
|
||||||
Validate static session which is valid starting from next epoch
|
Validate static session which is valid starting from next epoch
|
||||||
"""
|
"""
|
||||||
allure.dynamic.title(
|
allure.dynamic.title(
|
||||||
f"Validate static session which is valid starting from next epoch for {request.node.callspec.id}"
|
"Validate static session which is valid starting from next epoch "
|
||||||
|
f"for {request.node.callspec.id}"
|
||||||
)
|
)
|
||||||
epoch = ensure_fresh_epoch(client_shell)
|
epoch = ensure_fresh_epoch(client_shell)
|
||||||
|
|
||||||
container = owner_wallet.containers[0]
|
container = storage_containers[0]
|
||||||
object_id = storage_objects[0].oid
|
object_id = storage_objects[0].oid
|
||||||
expiration = Lifetime(epoch + 2, epoch + 1, epoch)
|
expiration = Lifetime(epoch + 2, epoch + 1, epoch)
|
||||||
|
|
||||||
token_start_at_next_epoch = get_object_signed_token(
|
token_start_at_next_epoch = get_object_signed_token(
|
||||||
owner_wallet,
|
owner_wallet,
|
||||||
user_wallet,
|
user_wallet,
|
||||||
|
container,
|
||||||
storage_objects,
|
storage_objects,
|
||||||
HEAD_VERB,
|
ObjectVerb.HEAD,
|
||||||
client_shell,
|
client_shell,
|
||||||
prepare_tmp_dir,
|
prepare_tmp_dir,
|
||||||
expiration,
|
expiration,
|
||||||
|
@ -558,6 +549,7 @@ def test_static_session_already_expired(
|
||||||
owner_wallet: WalletFile,
|
owner_wallet: WalletFile,
|
||||||
user_wallet: WalletFile,
|
user_wallet: WalletFile,
|
||||||
client_shell: Shell,
|
client_shell: Shell,
|
||||||
|
storage_containers: list[str],
|
||||||
storage_objects: list[StorageObjectInfo],
|
storage_objects: list[StorageObjectInfo],
|
||||||
prepare_tmp_dir: str,
|
prepare_tmp_dir: str,
|
||||||
request: FixtureRequest,
|
request: FixtureRequest,
|
||||||
|
@ -570,15 +562,16 @@ def test_static_session_already_expired(
|
||||||
)
|
)
|
||||||
epoch = ensure_fresh_epoch(client_shell)
|
epoch = ensure_fresh_epoch(client_shell)
|
||||||
|
|
||||||
container = owner_wallet.containers[0]
|
container = storage_containers[0]
|
||||||
object_id = storage_objects[0].oid
|
object_id = storage_objects[0].oid
|
||||||
expiration = Lifetime(epoch - 1, epoch - 2, epoch - 2)
|
expiration = Lifetime(epoch - 1, epoch - 2, epoch - 2)
|
||||||
|
|
||||||
token_already_expired = get_object_signed_token(
|
token_already_expired = get_object_signed_token(
|
||||||
owner_wallet,
|
owner_wallet,
|
||||||
user_wallet,
|
user_wallet,
|
||||||
|
container,
|
||||||
storage_objects,
|
storage_objects,
|
||||||
HEAD_VERB,
|
ObjectVerb.HEAD,
|
||||||
client_shell,
|
client_shell,
|
||||||
prepare_tmp_dir,
|
prepare_tmp_dir,
|
||||||
expiration,
|
expiration,
|
||||||
|
@ -594,8 +587,9 @@ def test_static_session_already_expired(
|
||||||
def test_static_session_delete_verb(
|
def test_static_session_delete_verb(
|
||||||
user_wallet: WalletFile,
|
user_wallet: WalletFile,
|
||||||
client_shell: Shell,
|
client_shell: Shell,
|
||||||
|
storage_containers: list[str],
|
||||||
storage_objects: list[StorageObjectInfo],
|
storage_objects: list[StorageObjectInfo],
|
||||||
static_sessions: list[str],
|
static_sessions: dict[ObjectVerb, str],
|
||||||
request: FixtureRequest,
|
request: FixtureRequest,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
@ -611,7 +605,7 @@ def test_static_session_delete_verb(
|
||||||
storage_object.cid,
|
storage_object.cid,
|
||||||
storage_object.oid,
|
storage_object.oid,
|
||||||
client_shell,
|
client_shell,
|
||||||
session=static_sessions[DELETE_VERB],
|
session=static_sessions[ObjectVerb.DELETE],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -620,7 +614,7 @@ def test_static_session_put_verb(
|
||||||
user_wallet: WalletFile,
|
user_wallet: WalletFile,
|
||||||
client_shell: Shell,
|
client_shell: Shell,
|
||||||
storage_objects: list[StorageObjectInfo],
|
storage_objects: list[StorageObjectInfo],
|
||||||
static_sessions: list[str],
|
static_sessions: dict[ObjectVerb, str],
|
||||||
request: FixtureRequest,
|
request: FixtureRequest,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
@ -636,7 +630,7 @@ def test_static_session_put_verb(
|
||||||
storage_object.file_path,
|
storage_object.file_path,
|
||||||
storage_object.cid,
|
storage_object.cid,
|
||||||
client_shell,
|
client_shell,
|
||||||
session=static_sessions[PUT_VERB],
|
session=static_sessions[ObjectVerb.PUT],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -646,6 +640,7 @@ def test_static_session_invalid_issued_epoch(
|
||||||
owner_wallet: WalletFile,
|
owner_wallet: WalletFile,
|
||||||
user_wallet: WalletFile,
|
user_wallet: WalletFile,
|
||||||
client_shell: Shell,
|
client_shell: Shell,
|
||||||
|
storage_containers: list[str],
|
||||||
storage_objects: list[StorageObjectInfo],
|
storage_objects: list[StorageObjectInfo],
|
||||||
prepare_tmp_dir: str,
|
prepare_tmp_dir: str,
|
||||||
request: FixtureRequest,
|
request: FixtureRequest,
|
||||||
|
@ -658,15 +653,16 @@ def test_static_session_invalid_issued_epoch(
|
||||||
)
|
)
|
||||||
epoch = ensure_fresh_epoch(client_shell)
|
epoch = ensure_fresh_epoch(client_shell)
|
||||||
|
|
||||||
container = owner_wallet.containers[0]
|
container = storage_containers[0]
|
||||||
object_id = storage_objects[0].oid
|
object_id = storage_objects[0].oid
|
||||||
expiration = Lifetime(epoch + 10, 0, epoch + 1)
|
expiration = Lifetime(epoch + 10, 0, epoch + 1)
|
||||||
|
|
||||||
token_invalid_issue_time = get_object_signed_token(
|
token_invalid_issue_time = get_object_signed_token(
|
||||||
owner_wallet,
|
owner_wallet,
|
||||||
user_wallet,
|
user_wallet,
|
||||||
|
container,
|
||||||
storage_objects,
|
storage_objects,
|
||||||
HEAD_VERB,
|
ObjectVerb.HEAD,
|
||||||
client_shell,
|
client_shell,
|
||||||
prepare_tmp_dir,
|
prepare_tmp_dir,
|
||||||
expiration,
|
expiration,
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
import allure
|
||||||
|
import pytest
|
||||||
|
from file_helper import generate_file
|
||||||
|
from neofs_testlib.shell import Shell
|
||||||
|
from python_keywords.acl import (
|
||||||
|
EACLAccess,
|
||||||
|
EACLOperation,
|
||||||
|
EACLRole,
|
||||||
|
EACLRule,
|
||||||
|
create_eacl,
|
||||||
|
set_eacl,
|
||||||
|
wait_for_cache_expired,
|
||||||
|
)
|
||||||
|
from python_keywords.container import (
|
||||||
|
create_container,
|
||||||
|
delete_container,
|
||||||
|
get_container,
|
||||||
|
list_containers,
|
||||||
|
)
|
||||||
|
from python_keywords.object_access import can_put_object
|
||||||
|
from wallet import WalletFile
|
||||||
|
from wellknown_acl import PUBLIC_ACL
|
||||||
|
|
||||||
|
from steps.session_token import ContainerVerb, get_container_signed_token
|
||||||
|
|
||||||
|
|
||||||
|
class TestSessionTokenContainer:
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def static_sessions(
|
||||||
|
self,
|
||||||
|
owner_wallet: WalletFile,
|
||||||
|
user_wallet: WalletFile,
|
||||||
|
client_shell: Shell,
|
||||||
|
prepare_tmp_dir: str,
|
||||||
|
) -> dict[ContainerVerb, str]:
|
||||||
|
"""
|
||||||
|
Returns dict with static session token file paths for all verbs with default lifetime
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
verb: get_container_signed_token(
|
||||||
|
owner_wallet, user_wallet, verb, client_shell, prepare_tmp_dir
|
||||||
|
)
|
||||||
|
for verb in ContainerVerb
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_static_session_token_container_create(
|
||||||
|
self,
|
||||||
|
client_shell: Shell,
|
||||||
|
owner_wallet: WalletFile,
|
||||||
|
user_wallet: WalletFile,
|
||||||
|
static_sessions: dict[ContainerVerb, str],
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Validate static session with create operation
|
||||||
|
"""
|
||||||
|
with allure.step("Create container with static session token"):
|
||||||
|
cid = create_container(
|
||||||
|
user_wallet.path,
|
||||||
|
session_token=static_sessions[ContainerVerb.CREATE],
|
||||||
|
shell=client_shell,
|
||||||
|
wait_for_creation=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
container_info: dict[str, str] = get_container(owner_wallet.path, cid, shell=client_shell)
|
||||||
|
assert container_info["ownerID"] == owner_wallet.get_address()
|
||||||
|
|
||||||
|
assert cid not in list_containers(user_wallet.path, shell=client_shell)
|
||||||
|
assert cid in list_containers(owner_wallet.path, shell=client_shell)
|
||||||
|
|
||||||
|
@pytest.mark.skip("Failed with timeout")
|
||||||
|
def test_static_session_token_container_create_with_other_verb(
|
||||||
|
self,
|
||||||
|
client_shell: Shell,
|
||||||
|
owner_wallet: WalletFile,
|
||||||
|
user_wallet: WalletFile,
|
||||||
|
static_sessions: dict[ContainerVerb, str],
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Validate static session without create operation
|
||||||
|
"""
|
||||||
|
with allure.step("Try create container with static session token without PUT rule"):
|
||||||
|
for verb in [verb for verb in ContainerVerb if verb != ContainerVerb.CREATE]:
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
create_container(
|
||||||
|
user_wallet.path,
|
||||||
|
session_token=static_sessions[verb],
|
||||||
|
shell=client_shell,
|
||||||
|
wait_for_creation=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
@pytest.mark.skip("Failed with timeout")
|
||||||
|
def test_static_session_token_container_create_with_other_wallet(
|
||||||
|
self,
|
||||||
|
client_shell: Shell,
|
||||||
|
owner_wallet: WalletFile,
|
||||||
|
stranger_wallet: WalletFile,
|
||||||
|
static_sessions: dict[ContainerVerb, str],
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Validate static session with create operation for other wallet
|
||||||
|
"""
|
||||||
|
with allure.step("Try create container with static session token without PUT rule"):
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
create_container(
|
||||||
|
stranger_wallet.path,
|
||||||
|
session_token=static_sessions[ContainerVerb.CREATE],
|
||||||
|
shell=client_shell,
|
||||||
|
wait_for_creation=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_static_session_token_container_delete(
|
||||||
|
self,
|
||||||
|
client_shell: Shell,
|
||||||
|
owner_wallet: WalletFile,
|
||||||
|
user_wallet: WalletFile,
|
||||||
|
static_sessions: dict[ContainerVerb, str],
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Validate static session with delete operation
|
||||||
|
"""
|
||||||
|
with allure.step("Create container"):
|
||||||
|
cid = create_container(owner_wallet.path, shell=client_shell, wait_for_creation=False)
|
||||||
|
with allure.step("Delete container with static session token"):
|
||||||
|
delete_container(
|
||||||
|
wallet=user_wallet.path,
|
||||||
|
cid=cid,
|
||||||
|
session_token=static_sessions[ContainerVerb.DELETE],
|
||||||
|
shell=client_shell,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert cid not in list_containers(owner_wallet.path, shell=client_shell)
|
||||||
|
|
||||||
|
def test_static_session_token_container_set_eacl(
|
||||||
|
self,
|
||||||
|
client_shell: Shell,
|
||||||
|
owner_wallet: WalletFile,
|
||||||
|
user_wallet: WalletFile,
|
||||||
|
stranger_wallet: WalletFile,
|
||||||
|
static_sessions: dict[ContainerVerb, str],
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Validate static session with set eacl operation
|
||||||
|
"""
|
||||||
|
with allure.step("Create container"):
|
||||||
|
cid = create_container(owner_wallet.path, basic_acl=PUBLIC_ACL, shell=client_shell)
|
||||||
|
file_path = generate_file()
|
||||||
|
assert can_put_object(stranger_wallet.path, cid, file_path, client_shell)
|
||||||
|
|
||||||
|
with allure.step(f"Deny all operations for other via eACL"):
|
||||||
|
eacl_deny = [
|
||||||
|
EACLRule(access=EACLAccess.DENY, role=EACLRole.OTHERS, operation=op)
|
||||||
|
for op in EACLOperation
|
||||||
|
]
|
||||||
|
set_eacl(
|
||||||
|
user_wallet.path,
|
||||||
|
cid,
|
||||||
|
create_eacl(cid, eacl_deny, shell=client_shell),
|
||||||
|
shell=client_shell,
|
||||||
|
session_token=static_sessions[ContainerVerb.SETEACL],
|
||||||
|
)
|
||||||
|
wait_for_cache_expired()
|
||||||
|
|
||||||
|
assert not can_put_object(stranger_wallet.path, cid, file_path, client_shell)
|
|
@ -130,7 +130,13 @@ def get_eacl(wallet_path: str, cid: str, shell: Shell) -> Optional[str]:
|
||||||
|
|
||||||
|
|
||||||
@allure.title("Set extended ACL")
|
@allure.title("Set extended ACL")
|
||||||
def set_eacl(wallet_path: str, cid: str, eacl_table_path: str, shell: Shell) -> None:
|
def set_eacl(
|
||||||
|
wallet_path: str,
|
||||||
|
cid: str,
|
||||||
|
eacl_table_path: str,
|
||||||
|
shell: Shell,
|
||||||
|
session_token: Optional[str] = None,
|
||||||
|
) -> None:
|
||||||
cli = NeofsCli(shell, NEOFS_CLI_EXEC, WALLET_CONFIG)
|
cli = NeofsCli(shell, NEOFS_CLI_EXEC, WALLET_CONFIG)
|
||||||
cli.container.set_eacl(
|
cli.container.set_eacl(
|
||||||
wallet=wallet_path,
|
wallet=wallet_path,
|
||||||
|
@ -138,6 +144,7 @@ def set_eacl(wallet_path: str, cid: str, eacl_table_path: str, shell: Shell) ->
|
||||||
cid=cid,
|
cid=cid,
|
||||||
table=eacl_table_path,
|
table=eacl_table_path,
|
||||||
await_mode=True,
|
await_mode=True,
|
||||||
|
session=session_token,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -165,7 +165,9 @@ def get_container(
|
||||||
@allure.step("Delete Container")
|
@allure.step("Delete Container")
|
||||||
# TODO: make the error message about a non-found container more user-friendly
|
# TODO: make the error message about a non-found container more user-friendly
|
||||||
# https://github.com/nspcc-dev/neofs-contract/issues/121
|
# https://github.com/nspcc-dev/neofs-contract/issues/121
|
||||||
def delete_container(wallet: str, cid: str, shell: Shell, force: bool = False) -> None:
|
def delete_container(
|
||||||
|
wallet: str, cid: str, shell: Shell, force: bool = False, session_token: Optional[str] = None
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
A wrapper for `neofs-cli container delete` call.
|
A wrapper for `neofs-cli container delete` call.
|
||||||
Args:
|
Args:
|
||||||
|
@ -173,11 +175,14 @@ def delete_container(wallet: str, cid: str, shell: Shell, force: bool = False) -
|
||||||
cid (str): ID of the container to delete
|
cid (str): ID of the container to delete
|
||||||
shell: executor for cli command
|
shell: executor for cli command
|
||||||
force (bool): do not check whether container contains locks and remove immediately
|
force (bool): do not check whether container contains locks and remove immediately
|
||||||
|
session_token: a path to session token file
|
||||||
This function doesn't return anything.
|
This function doesn't return anything.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cli = NeofsCli(shell, NEOFS_CLI_EXEC, WALLET_CONFIG)
|
cli = NeofsCli(shell, NEOFS_CLI_EXEC, WALLET_CONFIG)
|
||||||
cli.container.delete(wallet=wallet, cid=cid, rpc_endpoint=NEOFS_ENDPOINT, force=force)
|
cli.container.delete(
|
||||||
|
wallet=wallet, cid=cid, rpc_endpoint=NEOFS_ENDPOINT, force=force, session=session_token
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _parse_cid(output: str) -> str:
|
def _parse_cid(output: str) -> str:
|
||||||
|
|
|
@ -4,7 +4,7 @@ import os
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
import uuid
|
import uuid
|
||||||
from typing import Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
import allure
|
import allure
|
||||||
import json_transformers
|
import json_transformers
|
||||||
|
@ -406,7 +406,7 @@ def get_netmap_netinfo(
|
||||||
address: Optional[str] = None,
|
address: Optional[str] = None,
|
||||||
ttl: Optional[int] = None,
|
ttl: Optional[int] = None,
|
||||||
xhdr: Optional[dict] = None,
|
xhdr: Optional[dict] = None,
|
||||||
) -> dict[str, object]:
|
) -> dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Get netmap netinfo output from node
|
Get netmap netinfo output from node
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue