Skip to content

Commit 62508b4

Browse files
authored
Raise InvalidGrantError if no grant associated with auth code exists (#1476)
Previously, when invalidating an authorization code after it has been used, if for whatever reason the associated grant object no longer exists, an uncaught exception would be raised - Grant.DoesNotExist. This could be caused by concurrent requests being made using the same authorization token. We now handle this scenario gracefully by catching Grant.DoesNotExist and returning an InvalidGrantError.
1 parent aede24b commit 62508b4

File tree

4 files changed

+30
-5
lines changed

4 files changed

+30
-5
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,4 @@ pySilver
119119
Wouter Klein Heerenbrink
120120
Yaroslav Halchenko
121121
Yuri Savin
122+
Miriam Forner

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2424
* Update middleware, validators, and views to use token checksums instead of token for token retrieval and validation.
2525
* #1446 use generic models pk instead of id.
2626
* Bump oauthlib version to 3.2.0 and above
27+
* Update the OAuth2Validator's invalidate_authorization_code method to return an InvalidGrantError if the associated grant does not exist.
2728

2829
### Deprecated
2930
### Removed

oauth2_provider/oauth2_validators.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from jwcrypto import jws, jwt
2525
from jwcrypto.common import JWException
2626
from jwcrypto.jwt import JWTExpired
27-
from oauthlib.oauth2.rfc6749 import utils
27+
from oauthlib.oauth2.rfc6749 import errors, utils
2828
from oauthlib.openid import RequestValidator
2929

3030
from .exceptions import FatalClientError
@@ -318,10 +318,15 @@ def confirm_redirect_uri(self, client_id, code, redirect_uri, client, *args, **k
318318

319319
def invalidate_authorization_code(self, client_id, code, request, *args, **kwargs):
320320
"""
321-
Remove the temporary grant used to swap the authorization token
321+
Remove the temporary grant used to swap the authorization token.
322+
323+
:raises: InvalidGrantError if the grant does not exist.
322324
"""
323-
grant = Grant.objects.get(code=code, application=request.client)
324-
grant.delete()
325+
try:
326+
grant = Grant.objects.get(code=code, application=request.client)
327+
grant.delete()
328+
except Grant.DoesNotExist:
329+
raise errors.InvalidGrantError(request=request)
325330

326331
def validate_client_id(self, client_id, request, *args, **kwargs):
327332
"""

tests/test_oauth2_validators.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,15 @@
99
from django.utils import timezone
1010
from jwcrypto import jwt
1111
from oauthlib.common import Request
12+
from oauthlib.oauth2.rfc6749 import errors as rfc6749_errors
1213

1314
from oauth2_provider.exceptions import FatalClientError
14-
from oauth2_provider.models import get_access_token_model, get_application_model, get_refresh_token_model
15+
from oauth2_provider.models import (
16+
get_access_token_model,
17+
get_application_model,
18+
get_grant_model,
19+
get_refresh_token_model,
20+
)
1521
from oauth2_provider.oauth2_backends import get_oauthlib_core
1622
from oauth2_provider.oauth2_validators import OAuth2Validator
1723

@@ -28,6 +34,7 @@
2834
UserModel = get_user_model()
2935
Application = get_application_model()
3036
AccessToken = get_access_token_model()
37+
Grant = get_grant_model()
3138
RefreshToken = get_refresh_token_model()
3239

3340
CLEARTEXT_SECRET = "1234567890abcdefghijklmnopqrstuvwxyz"
@@ -578,3 +585,14 @@ def test_validate_id_token_bad_token_no_aud(oauth2_settings, mocker, oidc_key):
578585
validator = OAuth2Validator()
579586
status = validator.validate_id_token(token.serialize(), ["openid"], mocker.sentinel.request)
580587
assert status is False
588+
589+
590+
@pytest.mark.django_db
591+
def test_invalidate_authorization_token_returns_invalid_grant_error_when_grant_does_not_exist():
592+
client_id = "123"
593+
code = "12345"
594+
request = Request("/")
595+
assert Grant.objects.all().count() == 0
596+
with pytest.raises(rfc6749_errors.InvalidGrantError):
597+
validator = OAuth2Validator()
598+
validator.invalidate_authorization_code(client_id=client_id, code=code, request=request)

0 commit comments

Comments
 (0)