Skip to content

Commit 8561ce6

Browse files
authored
Fix JWT OIDC decode yet again (#3466)
PBENCH-1182 JWT added yet another `DecodeError` in our API Key validation path in some recent update. Instead of continuing to add specific errors to be converted into a specific internal exception, just handle all exceptions in the primary OIDC decode by attempting the token as an API key. If that fails, report the API key validation error, and re-raise the original OIDC error. (Note that `verify_auth` will in turn just report this error and act as if no authentication token was given.)
1 parent fb64f6f commit 8561ce6

File tree

3 files changed

+28
-57
lines changed

3 files changed

+28
-57
lines changed

lib/pbench/server/auth/__init__.py

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,6 @@ def __str__(self) -> str:
2727
return self.message
2828

2929

30-
class OpenIDTokenInvalid(Exception):
31-
pass
32-
33-
3430
class Connection:
3531
"""Helper connection class for use by an OpenIDClient instance."""
3632

@@ -359,23 +355,14 @@ def token_introspect(self, token: str) -> JSON:
359355
"sub": <user_id>
360356
}
361357
"""
362-
try:
363-
return jwt.decode(
364-
token,
365-
self._pem_public_key,
366-
algorithms=[self._TOKEN_ALG],
367-
audience=[self.client_id],
368-
options={
369-
"verify_signature": True,
370-
"verify_aud": True,
371-
"verify_exp": True,
372-
},
373-
)
374-
except (
375-
jwt.ExpiredSignatureError,
376-
jwt.InvalidSignatureError,
377-
jwt.InvalidAudienceError,
378-
jwt.InvalidAlgorithmError,
379-
ValueError,
380-
) as exc:
381-
raise OpenIDTokenInvalid() from exc
358+
return jwt.decode(
359+
token,
360+
self._pem_public_key,
361+
algorithms=[self._TOKEN_ALG],
362+
audience=[self.client_id],
363+
options={
364+
"verify_signature": True,
365+
"verify_aud": True,
366+
"verify_exp": True,
367+
},
368+
)

lib/pbench/server/auth/auth.py

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from flask_restful import abort
77

88
from pbench.server import PbenchServerConfig
9-
from pbench.server.auth import OpenIDClient, OpenIDTokenInvalid
9+
from pbench.server.auth import OpenIDClient
1010
from pbench.server.database.models.api_keys import APIKey
1111
from pbench.server.database.models.users import User
1212

@@ -143,14 +143,15 @@ def verify_auth_oidc(auth_token: str) -> Optional[User]:
143143
"""
144144
try:
145145
token_payload = oidc_client.token_introspect(token=auth_token)
146-
except OpenIDTokenInvalid:
147-
# The token is not a valid access token, fall through.
148-
pass
149146
except Exception:
150-
current_app.logger.exception(
151-
"Unexpected exception occurred while verifying the auth token {}",
152-
auth_token,
153-
)
147+
try:
148+
return verify_auth_api_key(auth_token)
149+
except Exception:
150+
current_app.logger.exception(
151+
"Unexpected exception occurred while verifying the API key {}",
152+
auth_token,
153+
)
154+
raise
154155
else:
155156
# Extract what we want to cache from the access token
156157
user_id = token_payload["sub"]
@@ -168,12 +169,4 @@ def verify_auth_oidc(auth_token: str) -> Optional[User]:
168169
user.update(username=username, roles=roles)
169170
return user
170171

171-
try:
172-
return verify_auth_api_key(auth_token)
173-
except Exception:
174-
current_app.logger.exception(
175-
"Unexpected exception occurred while verifying the API key {}",
176-
auth_token,
177-
)
178-
179172
return None

lib/pbench/test/unit/server/auth/test_auth.py

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,7 @@
1212

1313
from pbench.server import JSON
1414
import pbench.server.auth
15-
from pbench.server.auth import (
16-
Connection,
17-
OpenIDClient,
18-
OpenIDClientError,
19-
OpenIDTokenInvalid,
20-
)
15+
from pbench.server.auth import Connection, OpenIDClient, OpenIDClientError
2116
import pbench.server.auth.auth as Auth
2217
from pbench.test.unit.server import DRB_USER_ID
2318
from pbench.test.unit.server.conftest import jwt_secret
@@ -435,9 +430,8 @@ def test_token_introspect_exp(self, monkeypatch, rsa_keys):
435430
)
436431
oidc_client = OpenIDClient.construct_oidc_client(config)
437432

438-
with pytest.raises(OpenIDTokenInvalid) as exc:
433+
with pytest.raises(jwt.exceptions.ExpiredSignatureError):
439434
oidc_client.token_introspect(token)
440-
assert isinstance(exc.value.__cause__, jwt.exceptions.ExpiredSignatureError)
441435

442436
def test_token_introspect_aud(self, monkeypatch, rsa_keys):
443437
"""Verify .token_introspect() failure via audience error"""
@@ -449,9 +443,8 @@ def test_token_introspect_aud(self, monkeypatch, rsa_keys):
449443
config = mock_connection(monkeypatch, "them", public_key=rsa_keys["public_key"])
450444
oidc_client = OpenIDClient.construct_oidc_client(config)
451445

452-
with pytest.raises(OpenIDTokenInvalid) as exc:
446+
with pytest.raises(jwt.exceptions.InvalidAudienceError):
453447
oidc_client.token_introspect(token)
454-
assert isinstance(exc.value.__cause__, jwt.exceptions.InvalidAudienceError)
455448

456449
def test_token_introspect_sig(self, monkeypatch, rsa_keys):
457450
"""Verify .token_introspect() failure via signature error"""
@@ -465,10 +458,9 @@ def test_token_introspect_sig(self, monkeypatch, rsa_keys):
465458
)
466459
oidc_client = OpenIDClient.construct_oidc_client(config)
467460

468-
with pytest.raises(OpenIDTokenInvalid) as exc:
461+
with pytest.raises(jwt.exceptions.InvalidSignatureError):
469462
# Make the signature invalid.
470463
oidc_client.token_introspect(token + "1")
471-
assert isinstance(exc.value.__cause__, jwt.exceptions.InvalidSignatureError)
472464

473465
def test_token_introspect_alg(self, monkeypatch, rsa_keys):
474466
"""Verify .token_introspect() failure via algorithm error"""
@@ -483,9 +475,8 @@ def test_token_introspect_alg(self, monkeypatch, rsa_keys):
483475
)
484476
oidc_client = OpenIDClient.construct_oidc_client(config)
485477

486-
with pytest.raises(OpenIDTokenInvalid) as exc:
478+
with pytest.raises(jwt.exceptions.InvalidAlgorithmError):
487479
oidc_client.token_introspect(generated_api_key)
488-
assert isinstance(exc.value.__cause__, jwt.exceptions.InvalidAlgorithmError)
489480

490481

491482
@dataclass
@@ -671,7 +662,7 @@ def test_verify_auth_oidc_invalid(self, monkeypatch, rsa_keys, make_logger):
671662
monkeypatch.setattr(Auth, "oidc_client", oidc_client)
672663

673664
def tio_exc(token: str) -> JSON:
674-
raise OpenIDTokenInvalid()
665+
raise Exception("OIDC validation is disabled")
675666

676667
app = Flask("test-verify-auth-oidc-invalid")
677668
app.logger = make_logger
@@ -693,7 +684,7 @@ def test_verify_auth_api_key(
693684
monkeypatch.setattr(Auth, "oidc_client", oidc_client)
694685

695686
def tio_exc(token: str) -> JSON:
696-
raise OpenIDTokenInvalid()
687+
raise Exception("OIDC validation is disabled")
697688

698689
app = Flask("test_verify_auth_api_key")
699690
app.logger = make_logger
@@ -716,7 +707,7 @@ def test_verify_auth_api_key_invalid(
716707
monkeypatch.setattr(Auth, "oidc_client", oidc_client)
717708

718709
def tio_exc(token: str) -> JSON:
719-
raise OpenIDTokenInvalid()
710+
raise Exception("OIDC validation is disabled")
720711

721712
app = Flask("test_verify_auth_api_key_invalid")
722713
app.logger = make_logger

0 commit comments

Comments
 (0)