Skip to content

Commit a4455dd

Browse files
authored
🎨 Refactor Multitenant Manager errors and exception handling (openwallet-foundation#3323)
* 🚚 move `MultitenantManagerError` definition to error module Signed-off-by: ff137 <[email protected]> * ✨ implement `InvalidTokenError` and handle unauthorized attempts Signed-off-by: ff137 <[email protected]> * ✨ implement `MissingProfileError` Signed-off-by: ff137 <[email protected]> * ✨ implement `WalletAlreadyExistsError` Signed-off-by: ff137 <[email protected]> * 🎨 Signed-off-by: ff137 <[email protected]> * ✨ collectively handle the remaining `MultitenantManagerError`s: `MissingProfileError`, `WalletAlreadyExistsError`, `WalletKeyMissingError` Signed-off-by: ff137 <[email protected]> * 🎨 extend `MultitenantManagerError` in `WalletKeyMissingError` and set default message Signed-off-by: ff137 <[email protected]> * ✨ group HTTPBadRequest in error handling with MultitenantManagerError Signed-off-by: ff137 <[email protected]> * 🎨 re-add old todo from d90c141 Signed-off-by: ff137 <[email protected]> --------- Signed-off-by: ff137 <[email protected]>
1 parent 506089c commit a4455dd

File tree

6 files changed

+65
-21
lines changed

6 files changed

+65
-21
lines changed

acapy_agent/admin/server.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
from ..core.profile import Profile
2323
from ..ledger.error import LedgerConfigError, LedgerTransactionError
2424
from ..messaging.responder import BaseResponder
25-
from ..multitenant.base import BaseMultitenantManager, MultitenantManagerError
25+
from ..multitenant.base import BaseMultitenantManager
26+
from ..multitenant.error import InvalidTokenError, MultitenantManagerError
2627
from ..storage.base import BaseStorage
2728
from ..storage.error import StorageNotFoundError
2829
from ..storage.type import RECORD_TYPE_ACAPY_UPGRADING
@@ -149,6 +150,14 @@ async def ready_middleware(request: web.BaseRequest, handler: Coroutine):
149150
# redirect, typically / -> /api/doc
150151
LOGGER.info("Handler redirect to: %s", e.location)
151152
raise
153+
except (web.HTTPUnauthorized, jwt.InvalidTokenError, InvalidTokenError) as e:
154+
LOGGER.info(
155+
"Unauthorized access during %s %s: %s", request.method, request.path, e
156+
)
157+
raise web.HTTPUnauthorized(reason=str(e)) from e
158+
except (web.HTTPBadRequest, MultitenantManagerError) as e:
159+
LOGGER.info("Bad request during %s %s: %s", request.method, request.path, e)
160+
raise web.HTTPBadRequest(reason=str(e)) from e
152161
except asyncio.CancelledError:
153162
# redirection spawns new task and cancels old
154163
LOGGER.debug("Task cancelled")

acapy_agent/multitenant/admin/routes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ class CreateWalletRequestSchema(OpenAPISchema):
221221

222222
key_management_mode = fields.Str(
223223
dump_default=WalletRecord.MODE_MANAGED,
224+
# MTODO: add unmanaged mode once implemented
224225
validate=validate.OneOf((WalletRecord.MODE_MANAGED,)),
225226
metadata={
226227
"description": "Key management method to use for this wallet.",

acapy_agent/multitenant/admin/tests/test_routes.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
from ....messaging.models.base import BaseModelError
1212
from ....storage.error import StorageError, StorageNotFoundError
1313
from ....wallet.models.wallet_record import WalletRecord
14-
from ...base import BaseMultitenantManager, MultitenantManagerError
14+
from ...base import BaseMultitenantManager
15+
from ...error import MultitenantManagerError
1516
from .. import routes as test_module
1617

1718

acapy_agent/multitenant/base.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import jwt
99

1010
from ..config.injection_context import InjectionContext
11-
from ..core.error import BaseError
1211
from ..core.profile import Profile, ProfileSession
1312
from ..protocols.coordinate_mediation.v1_0.manager import (
1413
MediationManager,
@@ -21,27 +20,28 @@
2120
from ..transport.wire_format import BaseWireFormat
2221
from ..wallet.base import BaseWallet
2322
from ..wallet.models.wallet_record import WalletRecord
24-
from .error import WalletKeyMissingError
23+
from .error import (
24+
InvalidTokenError,
25+
MissingProfileError,
26+
WalletAlreadyExistsError,
27+
WalletKeyMissingError,
28+
)
2529

2630
LOGGER = logging.getLogger(__name__)
2731

2832

29-
class MultitenantManagerError(BaseError):
30-
"""Generic multitenant error."""
31-
32-
3333
class BaseMultitenantManager(ABC):
3434
"""Base class for handling multitenancy."""
3535

36-
def __init__(self, profile: Profile):
36+
def __init__(self, profile: Optional[Profile]):
3737
"""Initialize base multitenant Manager.
3838
3939
Args:
4040
profile: The profile for this manager
4141
"""
42-
self._profile = profile
4342
if not profile:
44-
raise MultitenantManagerError("Missing profile")
43+
raise MissingProfileError()
44+
self._profile = profile
4545

4646
@property
4747
@abstractmethod
@@ -93,6 +93,7 @@ def get_webhook_urls(
9393
Args:
9494
base_context: Base context to get base_webhook_urls
9595
wallet_record: Wallet record to get dispatch_type and webhook_urls
96+
9697
Returns:
9798
webhook urls according to dispatch_type
9899
"""
@@ -156,7 +157,7 @@ async def create_wallet(
156157
to not store the wallet key, or "managed" to store the wallet key
157158
158159
Raises:
159-
MultitenantManagerError: If the wallet name already exists
160+
WalletAlreadyExistsError: If the wallet name already exists
160161
161162
Returns:
162163
WalletRecord: The newly created wallet record
@@ -169,9 +170,7 @@ async def create_wallet(
169170
async with self._profile.session() as session:
170171
# Check if the wallet name already exists to avoid indy wallet errors
171172
if wallet_name and await self._wallet_name_exists(session, wallet_name):
172-
raise MultitenantManagerError(
173-
f"Wallet with name {wallet_name} already exists"
174-
)
173+
raise WalletAlreadyExistsError(wallet_name)
175174

176175
# In unmanaged mode we don't want to store the wallet key
177176
if key_management_mode == WalletRecord.MODE_UNMANAGED:
@@ -254,7 +253,7 @@ async def remove_wallet(self, wallet_id: str, wallet_key: Optional[str] = None):
254253

255254
wallet_key = wallet_key or wallet.wallet_key
256255
if wallet.requires_external_key and not wallet_key:
257-
raise WalletKeyMissingError("Missing key to open wallet")
256+
raise WalletKeyMissingError()
258257

259258
profile = await self.get_wallet_profile(
260259
self._profile.context,
@@ -353,7 +352,8 @@ async def get_profile_for_token(
353352
354353
Raises:
355354
WalletKeyMissingError: If the wallet_key is missing for an unmanaged wallet
356-
InvalidTokenError: If there is an exception while decoding the token
355+
InvalidTokenError: If the decoded token is invalid
356+
jwt.InvalidTokenError: If there is an exception while decoding the token
357357
358358
Returns:
359359
Profile associated with the token
@@ -378,7 +378,7 @@ async def get_profile_for_token(
378378
extra_settings["wallet.key"] = wallet_key
379379

380380
if wallet.jwt_iat and wallet.jwt_iat != iat:
381-
raise MultitenantManagerError("Token not valid")
381+
raise InvalidTokenError()
382382

383383
profile = await self.get_wallet_profile(context, wallet, extra_settings)
384384

acapy_agent/multitenant/error.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,38 @@
33
from ..core.error import BaseError
44

55

6-
class WalletKeyMissingError(BaseError):
6+
class MultitenantManagerError(BaseError):
7+
"""Generic multitenant error."""
8+
9+
10+
class InvalidTokenError(MultitenantManagerError):
11+
"""Exception raised for invalid tokens."""
12+
13+
def __init__(self, message: str = "Token not valid"):
14+
"""Initialize an instance of InvalidTokenError."""
15+
super().__init__(message)
16+
17+
18+
class MissingProfileError(MultitenantManagerError):
19+
"""Exception raised when a profile is missing."""
20+
21+
def __init__(self, message: str = "Missing profile"):
22+
"""Initialize an instance of MissingProfileError."""
23+
super().__init__(message)
24+
25+
26+
class WalletAlreadyExistsError(MultitenantManagerError):
27+
"""Exception raised when a wallet already exists."""
28+
29+
def __init__(self, wallet_name: str):
30+
"""Initialize an instance of WalletAlreadyExistsError."""
31+
message = f"Wallet with name {wallet_name} already exists"
32+
super().__init__(message)
33+
34+
35+
class WalletKeyMissingError(MultitenantManagerError):
736
"""Wallet key missing exception."""
37+
38+
def __init__(self, message: str = "Missing key to open wallet"):
39+
"""Initialize an instance of WalletKeyMissingError."""
40+
super().__init__(message)

acapy_agent/multitenant/tests/test_base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
from ...wallet.key_type import ED25519
2323
from ...wallet.models.wallet_record import WalletRecord
2424
from .. import base as test_module
25-
from ..base import BaseMultitenantManager, MultitenantManagerError
26-
from ..error import WalletKeyMissingError
25+
from ..base import BaseMultitenantManager
26+
from ..error import MultitenantManagerError, WalletKeyMissingError
2727

2828

2929
class MockMultitenantManager(BaseMultitenantManager):

0 commit comments

Comments
 (0)