163 lines
5.0 KiB
Python
163 lines
5.0 KiB
Python
"""
|
|
Default model implementations. Custom database or OAuth backends need to
|
|
implement these models with fields and and methods to be compatible with the
|
|
views in :attr:`provider.views`.
|
|
"""
|
|
|
|
from django.db import models
|
|
from django.conf import settings
|
|
from .. import constants
|
|
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
|
|
from .managers import AccessTokenManager
|
|
|
|
try:
|
|
from django.utils import timezone
|
|
except ImportError:
|
|
timezone = None
|
|
|
|
AUTH_USER_MODEL = getattr(settings, 'AUTH_USER_MODEL', 'auth.User')
|
|
|
|
|
|
class Client(models.Model):
|
|
"""
|
|
Default client implementation.
|
|
|
|
Expected fields:
|
|
|
|
* :attr:`user`
|
|
* :attr:`name`
|
|
* :attr:`url`
|
|
* :attr:`redirect_url`
|
|
* :attr:`client_id`
|
|
* :attr:`client_secret`
|
|
* :attr:`client_type`
|
|
|
|
Clients are outlined in the :rfc:`2` and its subsections.
|
|
"""
|
|
user = models.ForeignKey(AUTH_USER_MODEL, related_name='oauth2_client',
|
|
blank=True, null=True)
|
|
name = models.CharField(max_length=255, blank=True)
|
|
url = models.URLField(help_text="Your application's URL.")
|
|
redirect_uri = models.URLField(help_text="Your application's callback URL")
|
|
client_id = models.CharField(max_length=255, default=short_token)
|
|
client_secret = models.CharField(max_length=255, default=long_token)
|
|
client_type = models.IntegerField(choices=CLIENT_TYPES)
|
|
|
|
def __unicode__(self):
|
|
return self.redirect_uri
|
|
|
|
def get_default_token_expiry(self):
|
|
public = (self.client_type == 1)
|
|
return get_token_expiry(public)
|
|
|
|
|
|
class Grant(models.Model):
|
|
"""
|
|
Default grant implementation. A grant is a code that can be swapped for an
|
|
access token. Grants have a limited lifetime as defined by
|
|
:attr:`provider.constants.EXPIRE_CODE_DELTA` and outlined in
|
|
:rfc:`4.1.2`
|
|
|
|
Expected fields:
|
|
|
|
* :attr:`user`
|
|
* :attr:`client` - :class:`Client`
|
|
* :attr:`code`
|
|
* :attr:`expires` - :attr:`datetime.datetime`
|
|
* :attr:`redirect_uri`
|
|
* :attr:`scope`
|
|
"""
|
|
user = models.ForeignKey(AUTH_USER_MODEL)
|
|
client = models.ForeignKey(Client)
|
|
code = models.CharField(max_length=255, default=long_token)
|
|
expires = models.DateTimeField(default=get_code_expiry)
|
|
redirect_uri = models.CharField(max_length=255, blank=True)
|
|
scope = models.IntegerField(default=0)
|
|
|
|
def __unicode__(self):
|
|
return self.code
|
|
|
|
|
|
class AccessToken(models.Model):
|
|
"""
|
|
Default access token implementation. An access token is a time limited
|
|
token to access a user's resources.
|
|
|
|
Access tokens are outlined :rfc:`5`.
|
|
|
|
Expected fields:
|
|
|
|
* :attr:`user`
|
|
* :attr:`token`
|
|
* :attr:`client` - :class:`Client`
|
|
* :attr:`expires` - :attr:`datetime.datetime`
|
|
* :attr:`scope`
|
|
|
|
Expected methods:
|
|
|
|
* :meth:`get_expire_delta` - returns an integer representing seconds to
|
|
expiry
|
|
"""
|
|
user = models.ForeignKey(AUTH_USER_MODEL)
|
|
token = models.CharField(max_length=255, default=long_token, db_index=True)
|
|
client = models.ForeignKey(Client)
|
|
expires = models.DateTimeField()
|
|
scope = models.IntegerField(default=constants.SCOPES[0][0],
|
|
choices=constants.SCOPES)
|
|
|
|
objects = AccessTokenManager()
|
|
|
|
def __unicode__(self):
|
|
return self.token
|
|
|
|
def save(self, *args, **kwargs):
|
|
if not self.expires:
|
|
self.expires = self.client.get_default_token_expiry()
|
|
super(AccessToken, self).save(*args, **kwargs)
|
|
|
|
def get_expire_delta(self, reference=None):
|
|
"""
|
|
Return the number of seconds until this token expires.
|
|
"""
|
|
if reference is None:
|
|
reference = now()
|
|
expiration = self.expires
|
|
|
|
if timezone:
|
|
if timezone.is_aware(reference) and timezone.is_naive(expiration):
|
|
# MySQL doesn't support timezone for datetime fields
|
|
# so we assume that the date was stored in the UTC timezone
|
|
expiration = timezone.make_aware(expiration, timezone.utc)
|
|
elif timezone.is_naive(reference) and timezone.is_aware(expiration):
|
|
reference = timezone.make_aware(reference, timezone.utc)
|
|
|
|
timedelta = expiration - reference
|
|
return timedelta.days*86400 + timedelta.seconds
|
|
|
|
|
|
class RefreshToken(models.Model):
|
|
"""
|
|
Default refresh token implementation. A refresh token can be swapped for a
|
|
new access token when said token expires.
|
|
|
|
Expected fields:
|
|
|
|
* :attr:`user`
|
|
* :attr:`token`
|
|
* :attr:`access_token` - :class:`AccessToken`
|
|
* :attr:`client` - :class:`Client`
|
|
* :attr:`expired` - ``boolean``
|
|
"""
|
|
user = models.ForeignKey(AUTH_USER_MODEL)
|
|
token = models.CharField(max_length=255, default=long_token)
|
|
access_token = models.OneToOneField(AccessToken,
|
|
related_name='refresh_token')
|
|
client = models.ForeignKey(Client)
|
|
expired = models.BooleanField(default=False)
|
|
|
|
def __unicode__(self):
|
|
return self.token
|