Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions oauth2_provider/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,12 +434,10 @@ def get_refresh_token_model():
return apps.get_model(oauth2_settings.REFRESH_TOKEN_MODEL)


def clear_expired():
now = timezone.now()
def get_refresh_expire_at():
""" Return the datetime before which refresh tokens are expired. """
refresh_expire_at = None
access_token_model = get_access_token_model()
refresh_token_model = get_refresh_token_model()
grant_model = get_grant_model()

REFRESH_TOKEN_EXPIRE_SECONDS = oauth2_settings.REFRESH_TOKEN_EXPIRE_SECONDS
if REFRESH_TOKEN_EXPIRE_SECONDS:
if not isinstance(REFRESH_TOKEN_EXPIRE_SECONDS, timedelta):
Expand All @@ -448,7 +446,17 @@ def clear_expired():
except TypeError:
e = "REFRESH_TOKEN_EXPIRE_SECONDS must be either a timedelta or seconds"
raise ImproperlyConfigured(e)
refresh_expire_at = now - REFRESH_TOKEN_EXPIRE_SECONDS
refresh_expire_at = timezone.now() - REFRESH_TOKEN_EXPIRE_SECONDS

return refresh_expire_at


def clear_expired():
now = timezone.now()
access_token_model = get_access_token_model()
refresh_token_model = get_refresh_token_model()
grant_model = get_grant_model()
refresh_expire_at = get_refresh_expire_at()

with transaction.atomic():
if refresh_expire_at:
Expand Down
28 changes: 19 additions & 9 deletions oauth2_provider/views/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import logging

from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Q
from django.http import HttpResponse
from django.utils import timezone
from django.utils.decorators import method_decorator
Expand All @@ -12,7 +13,9 @@
from ..exceptions import OAuthToolkitError
from ..forms import AllowForm
from ..http import OAuth2ResponseRedirect
from ..models import get_access_token_model, get_application_model, get_refresh_token_model
from ..models import (
get_access_token_model, get_application_model,
get_refresh_token_model, get_refresh_expire_at)
from ..scopes import get_scopes_backend
from ..settings import oauth2_settings
from ..signals import app_authorized
Expand Down Expand Up @@ -185,17 +188,24 @@ def get(self, request, *args, **kwargs):
return self.redirect(uri, application)

elif require_approval == "auto":
now = timezone.now()
tokens = get_access_token_model().objects.filter(
user=request.user,
application=kwargs["application"],
expires__gt=timezone.now()
).all()

refresh_tokens = get_refresh_token_model().objects.filter(
user=request.user,
application=kwargs["application"]
).exclude(revoked__lt=timezone.now()).all()
tokens = list(tokens) + [r.access_token for r in refresh_tokens]
).filter(
# token is not expired
Q(expires__gt=now) |
# OR refresh_token exists and is not revoked
(Q(refresh_token__isnull=False) &
~Q(refresh_token__revoked__lt=now))
)

# exclude if refresh token is expired
refresh_expire_at = get_refresh_expire_at()
if refresh_expire_at:
tokens = tokens.exclude(
Q(refresh_token__created__lt=refresh_expire_at)
)

# check past authorizations regarded the same scopes as the current one
for token in tokens:
Expand Down
34 changes: 26 additions & 8 deletions tests/test_authorization_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,18 @@ def test_pre_auth_approval_prompt(self):
expires=timezone.now() + datetime.timedelta(days=1),
scope="read write"
)
reftok = RefreshToken.objects.create(
user=self.test_user, token="0123456789",
application=self.application,
access_token=tok,
created=timezone.now() - datetime.timedelta(seconds=2000)
)

# WIP: This fails, reporting no related object. Why?
# I think new tests are failing due to this issue. @madprime
tok = AccessToken.objects.get(id=tok.id)
print(tok.refresh_token)

self.client.login(username="test_user", password="123456")
query_string = urlencode({
"client_id": self.application.client_id,
Expand All @@ -197,19 +209,25 @@ def test_pre_auth_approval_prompt(self):
url = "{url}?{qs}".format(url=reverse("oauth2_provider:authorize"), qs=query_string)
response = self.client.get(url)
self.assertEqual(response.status_code, 302)
# user already authorized the application, but with different scopes: prompt them.
tok.scope = "read"
tok.save()
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
tok.scope = "read write"
# access token expired but valid refresh token exists
tok.expires = timezone.now() - datetime.timedelta(days=1)
tok.save()
reftok = RefreshToken.objects.create(
user=self.test_user, token="0123456789",
application=self.application,
access_token=tok
)
response = self.client.get(url)
self.assertEqual(response.status_code, 302)
# user already authorized the application, but with different scopes: prompt them.
tok.scope = "read"
tok.save()
# refresh token invalid due to expiration
oauth2_settings.REFRESH_TOKEN_EXPIRE_SECONDS = 1000
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
oauth2_settings.REFRESH_TOKEN_EXPIRE_SECONDS = None
# refresh token revoked
reftok.revoked = timezone.now() - datetime.timedelta(seconds=10)
reftok.save()
response = self.client.get(url)
self.assertEqual(response.status_code, 200)

Expand Down