Merge pull request #50 from caffeinehit/pr/48
Implement OAUTH_DELETE_EXPIRED setting
This commit is contained in:
commit
2c345f2f5b
14
docs/api.rst
14
docs/api.rst
|
@ -28,7 +28,7 @@
|
|||
|
||||
:settings: `OAUTH_EXPIRE_DELTA`
|
||||
:default: `datetime.timedelta(days=365)`
|
||||
|
||||
|
||||
The time to expiry for access tokens as outlined in :rfc:`4.2.2` and
|
||||
:rfc:`5.1`.
|
||||
|
||||
|
@ -36,9 +36,17 @@
|
|||
|
||||
:settings: `OAUTH_EXPIRE_CODE_DELTA`
|
||||
:default: `datetime.timedelta(seconds=10*60)`
|
||||
|
||||
|
||||
The time to expiry for an authorization code grant as outlined in :rfc:`4.1.2`.
|
||||
|
||||
|
||||
.. attribute:: DELETE_EXPIRED
|
||||
|
||||
:settings: `OAUTH_DELETE_EXPIRED`
|
||||
:default: `False`
|
||||
|
||||
To remove expired tokens immediately instead of letting them persist, set
|
||||
to `True`.
|
||||
|
||||
.. attribute:: ENFORCE_SECURE
|
||||
|
||||
:settings: `OAUTH_ENFORCE_SECURE`
|
||||
|
|
|
@ -26,11 +26,15 @@ DEFAULT_SCOPES = (
|
|||
SCOPES = getattr(settings, 'OAUTH_SCOPES', DEFAULT_SCOPES)
|
||||
|
||||
EXPIRE_DELTA = getattr(settings, 'OAUTH_EXPIRE_DELTA', timedelta(days=365))
|
||||
|
||||
# Expiry delta for public clients (which typically have shorter lived tokens)
|
||||
EXPIRE_DELTA_PUBLIC = getattr(settings, 'OAUTH_EXPIRE_DELTA_PUBLIC', timedelta(days=30))
|
||||
|
||||
EXPIRE_CODE_DELTA = getattr(settings, 'OAUTH_EXPIRE_CODE_DELTA', timedelta(seconds=10 * 60))
|
||||
|
||||
# Remove expired tokens immediately instead of letting them persist.
|
||||
DELETE_EXPIRED = getattr(settings, 'OAUTH_DELETE_EXPIRED', False)
|
||||
|
||||
ENFORCE_SECURE = getattr(settings, 'OAUTH_ENFORCE_SECURE', False)
|
||||
ENFORCE_CLIENT_SECURE = getattr(settings, 'OAUTH_ENFORCE_CLIENT_SECURE', True)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ views in :attr:`provider.views`.
|
|||
from django.db import models
|
||||
from django.conf import settings
|
||||
from .. import constants
|
||||
from ..constants import CLIENT_TYPES
|
||||
from ..constants import CLIENT_TYPES, DELETE_EXPIRED
|
||||
from ..utils import short_token, long_token, get_token_expiry
|
||||
from ..utils import get_code_expiry
|
||||
from ..utils import now
|
||||
|
|
|
@ -12,7 +12,7 @@ from ..compat import skipIfCustomUser
|
|||
from ..templatetags.scope import scopes
|
||||
from ..utils import now as date_now
|
||||
from .forms import ClientForm
|
||||
from .models import Client, Grant, AccessToken
|
||||
from .models import Client, Grant, AccessToken, RefreshToken
|
||||
from .backends import BasicClientBackend, RequestParamsClientBackend
|
||||
from .backends import AccessTokenBackend
|
||||
|
||||
|
@ -531,3 +531,71 @@ class ScopeTest(TestCase):
|
|||
names.sort()
|
||||
|
||||
self.assertEqual('read read+write write', ' '.join(names))
|
||||
|
||||
|
||||
class DeleteExpiredTest(BaseOAuth2TestCase):
|
||||
fixtures = ['test_oauth2']
|
||||
|
||||
def setUp(self):
|
||||
self._delete_expired = constants.DELETE_EXPIRED
|
||||
constants.DELETE_EXPIRED = True
|
||||
|
||||
def tearDown(self):
|
||||
constants.DELETE_EXPIRED = self._delete_expired
|
||||
|
||||
def test_clear_expired(self):
|
||||
self.login()
|
||||
|
||||
self._login_and_authorize()
|
||||
|
||||
response = self.client.get(self.redirect_url())
|
||||
|
||||
self.assertEqual(302, response.status_code)
|
||||
location = response['Location']
|
||||
self.assertFalse('error' in location)
|
||||
self.assertTrue('code' in location)
|
||||
|
||||
# verify that Grant with code exists
|
||||
code = urlparse.parse_qs(location)['code'][0]
|
||||
self.assertTrue(Grant.objects.filter(code=code).exists())
|
||||
|
||||
# use the code/grant
|
||||
response = self.client.post(self.access_token_url(), {
|
||||
'grant_type': 'authorization_code',
|
||||
'client_id': self.get_client().client_id,
|
||||
'client_secret': self.get_client().client_secret,
|
||||
'code': code})
|
||||
self.assertEquals(200, response.status_code)
|
||||
token = json.loads(response.content)
|
||||
self.assertTrue('access_token' in token)
|
||||
access_token = token['access_token']
|
||||
self.assertTrue('refresh_token' in token)
|
||||
refresh_token = token['refresh_token']
|
||||
|
||||
# make sure the grant is gone
|
||||
self.assertFalse(Grant.objects.filter(code=code).exists())
|
||||
# and verify that the AccessToken and RefreshToken exist
|
||||
self.assertTrue(AccessToken.objects.filter(token=access_token)
|
||||
.exists())
|
||||
self.assertTrue(RefreshToken.objects.filter(token=refresh_token)
|
||||
.exists())
|
||||
|
||||
# refresh the token
|
||||
response = self.client.post(self.access_token_url(), {
|
||||
'grant_type': 'refresh_token',
|
||||
'refresh_token': token['refresh_token'],
|
||||
'client_id': self.get_client().client_id,
|
||||
'client_secret': self.get_client().client_secret,
|
||||
})
|
||||
self.assertEqual(200, response.status_code)
|
||||
token = json.loads(response.content)
|
||||
self.assertTrue('access_token' in token)
|
||||
self.assertNotEquals(access_token, token['access_token'])
|
||||
self.assertTrue('refresh_token' in token)
|
||||
self.assertNotEquals(refresh_token, token['refresh_token'])
|
||||
|
||||
# make sure the orig AccessToken and RefreshToken are gone
|
||||
self.assertFalse(AccessToken.objects.filter(token=access_token)
|
||||
.exists())
|
||||
self.assertFalse(RefreshToken.objects.filter(token=refresh_token)
|
||||
.exists())
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from datetime import timedelta
|
||||
from django.core.urlresolvers import reverse
|
||||
from .. import constants
|
||||
from ..views import Capture, Authorize, Redirect
|
||||
from ..views import AccessToken as AccessTokenView, OAuthError
|
||||
from ..utils import now
|
||||
|
@ -116,13 +117,22 @@ class AccessTokenView(AccessTokenView):
|
|||
)
|
||||
|
||||
def invalidate_grant(self, grant):
|
||||
grant.expires = now() - timedelta(days=1)
|
||||
grant.save()
|
||||
if constants.DELETE_EXPIRED:
|
||||
grant.delete()
|
||||
else:
|
||||
grant.expires = now() - timedelta(days=1)
|
||||
grant.save()
|
||||
|
||||
def invalidate_refresh_token(self, rt):
|
||||
rt.expired = True
|
||||
rt.save()
|
||||
if constants.DELETE_EXPIRED:
|
||||
rt.delete()
|
||||
else:
|
||||
rt.expired = True
|
||||
rt.save()
|
||||
|
||||
def invalidate_access_token(self, at):
|
||||
at.expires = now() - timedelta(days=1)
|
||||
at.save()
|
||||
if constants.DELETE_EXPIRED:
|
||||
at.delete()
|
||||
else:
|
||||
at.expires = now() - timedelta(days=1)
|
||||
at.save()
|
||||
|
|
|
@ -492,6 +492,7 @@ class AccessToken(OAuthView, Mixin):
|
|||
"""
|
||||
rt = self.get_refresh_token_grant(request, data, client)
|
||||
|
||||
# this must be called first in case we need to purge expired tokens
|
||||
self.invalidate_refresh_token(rt)
|
||||
self.invalidate_access_token(rt.access_token)
|
||||
|
||||
|
|
Loading…
Reference in New Issue