Skip to content

Commit 23be1ad

Browse files
authored
JWTIdentity raises common error JWTIdentityError (#840)
1 parent 2356dc6 commit 23be1ad

File tree

3 files changed

+39
-4
lines changed

3 files changed

+39
-4
lines changed

.flake8

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ select = A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,B901,B902,B903,B950
1010
# W503: Mutually exclusive with W504.
1111
ignore = E226,E501,E722,W503
1212
per-file-ignores =
13+
# B011: assert False used for coverage skipping
1314
# S101: Pytest uses assert
14-
tests/*:S101
15+
tests/*:B011,S101
1516

1617
# flake8-import-order
1718
application-import-names = aiohttp_security

aiohttp_security/jwt_identity.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
"""
44

5-
from typing import Optional
5+
from typing import Optional, Tuple, Type
66

77
from aiohttp import web
88

@@ -11,14 +11,23 @@
1111
try:
1212
import jwt
1313
HAS_JWT = True
14+
_bases_error: Tuple[Type[jwt.exceptions.PyJWTError], ...]
15+
_bases_error = (jwt.exceptions.PyJWTError,)
1416
except ImportError: # pragma: no cover
1517
HAS_JWT = False
18+
_bases_error = ()
1619

1720

1821
AUTH_HEADER_NAME = 'Authorization'
1922
AUTH_SCHEME = 'Bearer '
2023

2124

25+
# This class inherits from ValueError to maintain backward compatibility
26+
# with previous versions of aiohttp-security
27+
class InvalidAuthorizationScheme(ValueError, *_bases_error): # type: ignore[misc]
28+
"""Exception when the auth method can't be read from header."""
29+
30+
2231
class JWTIdentityPolicy(AbstractIdentityPolicy):
2332
def __init__(self, secret: str, algorithm: str = "HS256", key: str = "login"):
2433
if not HAS_JWT:
@@ -34,8 +43,8 @@ async def identify(self, request: web.Request) -> Optional[str]:
3443
return None
3544

3645
if not header_identity.startswith(AUTH_SCHEME):
37-
raise ValueError("Invalid authorization scheme. "
38-
+ "Should be `{}<token>`".format(AUTH_SCHEME))
46+
raise InvalidAuthorizationScheme("Invalid authorization scheme. "
47+
"Should be `{}<token>`".format(AUTH_SCHEME))
3948

4049
token = header_identity.split(' ')[1].strip()
4150

tests/test_jwt_identity.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,28 @@ async def check(request):
8080
resp = await client.get('/', headers=headers)
8181
assert 400 == resp.status
8282
assert 'Invalid authorization scheme' in resp.reason
83+
84+
85+
async def test_identify_expired_signature(make_token, aiohttp_client):
86+
kwt_secret_key = "Key" # noqa: S105
87+
88+
token = make_token({"login": "Andrew", "exp": 0}, kwt_secret_key)
89+
90+
async def check(request):
91+
policy = request.app[IDENTITY_KEY]
92+
try:
93+
await policy.identify(request)
94+
except jwt.exceptions.PyJWTError as exc:
95+
raise web.HTTPBadRequest(reason=str(exc))
96+
97+
assert False
98+
99+
app = web.Application()
100+
_setup(app, JWTIdentityPolicy(kwt_secret_key), Autz())
101+
app.router.add_route("GET", "/", check)
102+
103+
client = await aiohttp_client(app)
104+
headers = {"Authorization": "Bearer {}".format(token)}
105+
resp = await client.get("/", headers=headers)
106+
assert 400 == resp.status
107+
assert "Signature has expired" in resp.reason

0 commit comments

Comments
 (0)