diff --git a/aries_cloudagent/config/argparse.py b/aries_cloudagent/config/argparse.py index 17a572dd1e..4b91b22aad 100644 --- a/aries_cloudagent/config/argparse.py +++ b/aries_cloudagent/config/argparse.py @@ -1634,7 +1634,7 @@ def add_arguments(self, parser: ArgumentParser): help=( 'Specify multitenancy configuration ("wallet_type" and "wallet_name"). ' 'For example: "{"wallet_type":"askar-profile","wallet_name":' - '"askar-profile-name"}"' + '"askar-profile-name", "key_derivation_method":"RAW"}"' '"wallet_name" is only used when "wallet_type" is "askar-profile"' ), ) @@ -1668,6 +1668,11 @@ def get_settings(self, args: Namespace): "wallet_name" ) + if multitenancyConfig.get("key_derivation_method"): + settings[ + "multitenant.key_derivation_method" + ] = multitenancyConfig.get("key_derivation_method") + return settings diff --git a/aries_cloudagent/multitenant/admin/routes.py b/aries_cloudagent/multitenant/admin/routes.py index 5df6f84cfd..e95bac1f59 100644 --- a/aries_cloudagent/multitenant/admin/routes.py +++ b/aries_cloudagent/multitenant/admin/routes.py @@ -3,25 +3,23 @@ from aiohttp import web from aiohttp_apispec import ( docs, - request_schema, match_info_schema, - response_schema, querystring_schema, + request_schema, + response_schema, ) -from marshmallow import fields, validate, validates_schema, ValidationError +from marshmallow import ValidationError, fields, validate, validates_schema from ...admin.request_context import AdminRequestContext -from ...messaging.valid import JSONWebToken, UUIDFour +from ...core.error import BaseError +from ...core.profile import ProfileManagerProvider from ...messaging.models.base import BaseModelError from ...messaging.models.openapi import OpenAPISchema +from ...messaging.valid import JSONWebToken, UUIDFour from ...multitenant.base import BaseMultitenantManager from ...storage.error import StorageError, StorageNotFoundError -from ...wallet.models.wallet_record import WalletRecord, WalletRecordSchema from ...wallet.error import WalletSettingsError - -from ...core.error import BaseError -from ...core.profile import ProfileManagerProvider - +from ...wallet.models.wallet_record import WalletRecord, WalletRecordSchema from ..error import WalletKeyMissingError @@ -58,6 +56,13 @@ class CreateWalletRequestSchema(OpenAPISchema): description="Master key used for key derivation.", example="MySecretKey123" ) + wallet_key_derivation = fields.Str( + description="Key derivation", + required=False, + example="RAW", + validate=validate.OneOf(["ARGON2I_MOD", "ARGON2I_INT", "RAW"]), + ) + wallet_type = fields.Str( description="Type of the wallet to create", example="indy", @@ -303,10 +308,13 @@ async def wallet_create(request: web.BaseRequest): label = body.get("label") image_url = body.get("image_url") + key_derivation = body.get("wallet_key_derivation") if label: settings["default_label"] = label if image_url: settings["image_url"] = image_url + if key_derivation: # allow lower levels to handle default + settings["wallet.key_derivation_method"] = key_derivation try: multitenant_mgr = context.profile.inject(BaseMultitenantManager) diff --git a/aries_cloudagent/multitenant/admin/tests/test_routes.py b/aries_cloudagent/multitenant/admin/tests/test_routes.py index 1ffa316e2b..98ad47dca2 100644 --- a/aries_cloudagent/multitenant/admin/tests/test_routes.py +++ b/aries_cloudagent/multitenant/admin/tests/test_routes.py @@ -142,6 +142,7 @@ async def test_wallets_list_query(self): async def test_wallet_create(self): body = { "wallet_name": "test", + "default_label": "test_label", "wallet_type": "indy", "wallet_key": "test", "key_management_mode": "managed", @@ -206,6 +207,7 @@ async def test_wallet_create_optional_default_fields(self): body = { "wallet_name": "test", "wallet_key": "test", + "wallet_key_derivation": "ARGON2I_MOD", "wallet_webhook_urls": [], "wallet_dispatch_type": "base", "label": "my_test_label", @@ -227,6 +229,32 @@ async def test_wallet_create_optional_default_fields(self): "image_url": body["image_url"], "wallet.webhook_urls": body["wallet_webhook_urls"], "wallet.dispatch_type": body["wallet_dispatch_type"], + "wallet.key_derivation_method": body["wallet_key_derivation"], + }, + WalletRecord.MODE_MANAGED, + ) + + async def test_wallet_create_raw_key_derivation(self): + body = { + "wallet_name": "test", + "wallet_key": "test", + "wallet_key_derivation": "RAW", + } + self.request.json = async_mock.CoroutineMock(return_value=body) + + with async_mock.patch.object(test_module.web, "json_response") as mock_response: + self.mock_multitenant_mgr.create_wallet = async_mock.CoroutineMock() + self.mock_multitenant_mgr.create_auth_token = async_mock.CoroutineMock() + + await test_module.wallet_create(self.request) + self.mock_multitenant_mgr.create_wallet.assert_called_once_with( + { + "wallet.type": "in_memory", + "wallet.name": body["wallet_name"], + "wallet.key": body["wallet_key"], + "wallet.key_derivation_method": body["wallet_key_derivation"], + "wallet.webhook_urls": [], + "wallet.dispatch_type": "base", }, WalletRecord.MODE_MANAGED, ) diff --git a/aries_cloudagent/multitenant/base.py b/aries_cloudagent/multitenant/base.py index a7abb4c31d..18fe63a9c5 100644 --- a/aries_cloudagent/multitenant/base.py +++ b/aries_cloudagent/multitenant/base.py @@ -184,26 +184,29 @@ async def create_wallet( ) await wallet_record.save(session) + try: + # provision wallet + profile = await self.get_wallet_profile( + self._profile.context, + wallet_record, + { + "wallet.key": wallet_key, + }, + provision=True, + ) - # provision wallet - profile = await self.get_wallet_profile( - self._profile.context, - wallet_record, - { - "wallet.key": wallet_key, - }, - provision=True, - ) - - # subwallet context - async with profile.session() as session: - wallet = session.inject(BaseWallet) - public_did_info = await wallet.get_public_did() + # subwallet context + async with profile.session() as session: + wallet = session.inject(BaseWallet) + public_did_info = await wallet.get_public_did() - if public_did_info: - await self.add_key( - wallet_record.wallet_id, public_did_info.verkey, skip_if_exists=True - ) + if public_did_info: + await self.add_key( + wallet_record.wallet_id, public_did_info.verkey, skip_if_exists=True + ) + except Exception: + await wallet_record.delete_record(session) + raise return wallet_record diff --git a/aries_cloudagent/wallet/models/wallet_record.py b/aries_cloudagent/wallet/models/wallet_record.py index 6240ea3ea1..b81866839a 100644 --- a/aries_cloudagent/wallet/models/wallet_record.py +++ b/aries_cloudagent/wallet/models/wallet_record.py @@ -83,6 +83,11 @@ def wallet_key(self) -> Optional[str]: """Accessor for the key of the wallet.""" return self.settings.get("wallet.key") + @property + def wallet_key_derivation_method(self): + """Accessor for the key derivation method of the wallet.""" + return self.settings.get("wallet.key_derivation_method") + @property def record_value(self) -> dict: """Accessor for the JSON record value generated for this record."""