diff --git a/robot/resources/lib/python_keywords/container.py b/robot/resources/lib/python_keywords/container.py index 0b1db7bb..9b19a7f9 100644 --- a/robot/resources/lib/python_keywords/container.py +++ b/robot/resources/lib/python_keywords/container.py @@ -11,6 +11,7 @@ import time from common import NEOFS_ENDPOINT, COMMON_PLACEMENT_RULE, NEOFS_CLI_EXEC, WALLET_PASS from cli_helpers import _cmd_run from data_formatters import dict_to_attrs +import json_transformers from robot.api.deco import keyword from robot.api import logger @@ -90,8 +91,8 @@ def list_containers(wallet: str): return output.split() -@keyword('Get Container Attributes') -def get_container_attributes(wallet: str, cid: str): +@keyword('Get Container') +def get_container(wallet: str, cid: str): """ A wrapper for `neofs-cli container get` call. It extracts container attributes and rearranges them to more compact view. @@ -110,7 +111,10 @@ def get_container_attributes(wallet: str, cid: str): attributes = dict() for attr in container_info['attributes']: attributes[attr['key']] = attr['value'] - return attributes + container_info['attributes'] = attributes + container_info['ownerID'] = json_transformers.json_reencode( + container_info['ownerID']['value']) + return container_info @keyword('Delete Container') diff --git a/robot/resources/lib/python_keywords/json_transformers.py b/robot/resources/lib/python_keywords/json_transformers.py index 6bfa0793..b1459795 100644 --- a/robot/resources/lib/python_keywords/json_transformers.py +++ b/robot/resources/lib/python_keywords/json_transformers.py @@ -101,6 +101,10 @@ def json_reencode(data: str): ''' return base58.b58encode(base64.b64decode(data)).decode("utf-8") + +def encode_for_json(data: str): + return base64.b64encode(base58.b58decode(data)).decode('utf-8') + def decode_common_fields(data: dict): ''' Despite of type (simple/complex Object, Storage Group, etc) every Object diff --git a/robot/resources/lib/python_keywords/neofs.py b/robot/resources/lib/python_keywords/neofs.py index 829e8400..bb56a893 100644 --- a/robot/resources/lib/python_keywords/neofs.py +++ b/robot/resources/lib/python_keywords/neofs.py @@ -103,53 +103,3 @@ def get_locode(): logger.info(f'Random locode chosen: {locode}') return locode - - -@keyword('Generate Session Token') -def generate_session_token(owner: str, pub_key: str, cid: str = "", wildcard: bool = False) -> str: - - file_path = f"{os.getcwd()}/{ASSETS_DIR}/{str(uuid.uuid4())}" - - owner_64 = base64.b64encode(base58.b58decode(owner)).decode('utf-8') - cid_64 = base64.b64encode(cid.encode('utf-8')).decode('utf-8') - pub_key_64 = base64.b64encode(bytes.fromhex(pub_key)).decode('utf-8') - id_64 = base64.b64encode(uuid.uuid4().bytes).decode('utf-8') - - session_token = { - "body":{ - "id":f"{id_64}", - "ownerID":{ - "value":f"{owner_64}" - }, - "lifetime":{ - "exp":"100000000", - "nbf":"0", - "iat":"0" - }, - "sessionKey":f"{pub_key_64}", - "container":{ - "verb":"PUT", - "wildcard": wildcard, - **({ "containerID":{"value":f"{cid_64}"} } if not wildcard 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 - - -@keyword ('Sign Session Token') -def sign_session_token(session_token: str, wallet: str, to_file: str=''): - if to_file: - to_file = f'--to {to_file}' - cmd = ( - f'{NEOFS_CLI_EXEC} util sign session-token --from {session_token} ' - f'-w {wallet} {to_file} --config {WALLET_PASS}' - ) - logger.info(f"cmd: {cmd}") - _cmd_run(cmd) diff --git a/robot/resources/lib/python_keywords/session_token.py b/robot/resources/lib/python_keywords/session_token.py new file mode 100644 index 00000000..624d72b0 --- /dev/null +++ b/robot/resources/lib/python_keywords/session_token.py @@ -0,0 +1,102 @@ +#!/usr/bin/python3 + +""" + This module contains keywords for work with session token. +""" + +import base64 +import json +import os +import uuid + +from neo3 import wallet +from common import WALLET_PASS, ASSETS_DIR +from cli_helpers import _cmd_run +import json_transformers + +from robot.api.deco import keyword +from robot.api import logger + +ROBOT_AUTO_KEYWORDS = False + +# path to neofs-cli executable +NEOFS_CLI_EXEC = os.getenv('NEOFS_CLI_EXEC', 'neofs-cli') + + +@keyword('Generate Session Token') +def generate_session_token(owner: str, session_wallet: str, cid: str='') -> 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 () 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 = f"{os.getcwd()}/{ASSETS_DIR}/{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"{base64.b64encode(cid.encode('utf-8')).decode('utf-8')}"} + } 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 + + +@keyword ('Sign Session Token') +def sign_session_token(session_token: str, wlt: str): + """ + This function signs the session token by the given wallet. + Args: + session_token(str): the path to the session token file + wlt(str): the path to the signing wallet + Returns: + (str): the path to the signed token + """ + signed_token = f"{os.getcwd()}/{ASSETS_DIR}/{uuid.uuid4()}" + cmd = ( + f'{NEOFS_CLI_EXEC} util sign session-token --from {session_token} ' + f'-w {wlt} --to {signed_token} --config {WALLET_PASS}' + ) + _cmd_run(cmd) + return signed_token diff --git a/robot/testsuites/integration/container/container_attributes.robot b/robot/testsuites/integration/container/container_attributes.robot index 3556b49f..3d85e471 100644 --- a/robot/testsuites/integration/container/container_attributes.robot +++ b/robot/testsuites/integration/container/container_attributes.robot @@ -54,9 +54,9 @@ Duplicated Container Attributes ##################################################### ${CID} = Create Container ${WALLET} attributes=${ATTR_SINGLE} - &{ATTRIBUTES} = Get Container Attributes ${WALLET} ${CID} + &{ATTRIBUTES} = Get Container ${WALLET} ${CID} Dictionary Should Contain Sub Dictionary - ... ${ATTRIBUTES} + ... ${ATTRIBUTES}[attributes] ... ${ATTR_SINGLE} ... msg="No expected container attributes found" diff --git a/robot/testsuites/integration/container/container_session_token.robot b/robot/testsuites/integration/container/container_session_token.robot index d54a3248..817a7856 100644 --- a/robot/testsuites/integration/container/container_session_token.robot +++ b/robot/testsuites/integration/container/container_session_token.robot @@ -1,19 +1,11 @@ *** Settings *** Variables common.py -Variables wellknown_acl.py Resource setup_teardown.robot Resource payment_operations.robot Library container.py -Library neofs.py - -Library Process -Library String -Library OperatingSystem - -*** Variables *** -${SIGNED_FILE} = ${ASSETS_DIR}/signed_token.json +Library session_token.py *** Test Cases *** @@ -24,25 +16,20 @@ Session Token for Container [Setup] Setup - ${WALLET} ${OWNER} ${_} = Prepare Wallet And Deposit - ${GEN_WALLET} ${GEN} ${_} = Prepare Wallet And Deposit + ${OWNER_WALLET} ${OWNER} ${_} = Prepare Wallet And Deposit + ${SESSION_WALLET} ${_} ${_} = Prepare Wallet And Deposit - ${UTIL} = Run Process ${NEOGO_EXECUTABLE} wallet dump-keys -w ${GEN_WALLET} shell=True - ${PUB_PART} = Get Line ${UTIL.stdout} 1 + ${SESSION_TOKEN} = Generate Session Token ${OWNER} ${SESSION_WALLET} + ${SIGNED_FILE} = Sign Session token ${SESSION_TOKEN} ${OWNER_WALLET} - ${SESSION_TOKEN} = Generate Session Token ${OWNER} ${PUB_PART} wildcard=True - Sign Session token ${SESSION_TOKEN} ${WALLET} ${SIGNED_FILE} - - ${CID} = Create Container ${WALLET} basic_acl=${PRIVATE_ACL_F} - ... session_token=${SIGNED_FILE} session_wallet=${GEN_WALLET} + ${CID} = Create Container ${OWNER_WALLET} + ... session_token=${SIGNED_FILE} session_wallet=${SESSION_WALLET} ######################## # Check container owner ######################## - ${CONTAINER_INFO} = Run Process ${NEOFS_CLI_EXEC} container get --cid ${CID} --wallet ${GEN_WALLET} --config ${WALLET_PASS} --rpc-endpoint ${NEOFS_ENDPOINT} shell=True - ${CID_OWNER_ID_LINE} = Get Line ${CONTAINER_INFO.stdout} 2 - @{CID_OWNER_ID} = Split String ${CID_OWNER_ID_LINE} - Should Be Equal As Strings ${OWNER} ${CID_OWNER_ID}[2] + &{ATTRS} = Get Container ${SESSION_WALLET} ${CID} + Should Be Equal As Strings ${OWNER} ${ATTRS}[ownerID] [Teardown] Teardown container_session_token