Skip to content

Commit

Permalink
Merge pull request #6 from spaceby/master
Browse files Browse the repository at this point in the history
Correction of warnings related to the use of the native date.
  • Loading branch information
roman-karpovich authored Jul 23, 2020
2 parents 386046c + d8881ef commit e497df6
Show file tree
Hide file tree
Showing 23 changed files with 157 additions and 100 deletions.
15 changes: 15 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[flake8]
max-line-length = 120
ignore =
; PyFlakes errors
; F405 name may be undefined, or defined from star imports: module
F405
W503
; does not apply to python3. https://github.com/PyCQA/bandit/issues/402
S322
; disable paranoidal checking for password/token in strings
S105
max-complexity = 10

exclude =
*/migrations
11 changes: 11 additions & 0 deletions .isort.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[settings]
line_length=120
multi_line_output=3
balanced_wrapping=true
not_skip=__init__.py
skip=migrations,deployer
include_trailing_comma=true

known_django=django
known_rest=rest_framework
sections=FUTURE,STDLIB,DJANGO,REST,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
39 changes: 16 additions & 23 deletions drf_secure_token/abstract_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from django.db import models
from django.utils import timezone
from django.utils.six import python_2_unicode_compatible

from rest_framework import exceptions

from drf_secure_token import checkers
Expand All @@ -13,7 +14,11 @@

@python_2_unicode_compatible
class BaseToken(models.Model):
key = models.CharField(max_length=40, unique=True, null=True, blank=True, default=None)
@staticmethod
def generate_key():
return str(uuid.uuid4())

key = models.CharField(max_length=40, unique=True, blank=True, default=generate_key.__func__)
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='user_auth_tokens', on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)

Expand All @@ -23,42 +28,30 @@ class Meta:
def __str__(self):
return self.key

@staticmethod
def generate_key():
return str(uuid.uuid4())

def save(self, *args, **kwargs):
if not self.pk:
self.key = self.generate_key()
return super(BaseToken, self).save(*args, **kwargs)

def check_token(self):
for checker in checkers.checkers:
if not checker.check(self):
raise exceptions.AuthenticationFailed(checker.error_message)


class ExpiredTokenMixin(models.Model):
expire_in = models.DateTimeField(default=timezone.now)
@staticmethod
def default_expire_time():
return timezone.now() + datetime.timedelta(seconds=token_settings.TOKEN_AGE)

expire_in = models.DateTimeField(default=default_expire_time.__func__)

class Meta:
abstract = True

def save(self, *args, **kwargs):
if not self.pk:
self.expire_in = timezone.now() + datetime.timedelta(seconds=token_settings.TOKEN_AGE)
super(ExpiredTokenMixin, self).save(*args, **kwargs)


class DyingTokenMixin(ExpiredTokenMixin):
dead_in = models.DateTimeField(default=timezone.now)
@staticmethod
def default_dead_time():
return ExpiredTokenMixin.default_expire_time() + datetime.timedelta(seconds=token_settings.MUTABLE_PERIOD)

dead_in = models.DateTimeField(default=default_dead_time.__func__)
marked_for_delete = models.BooleanField(default=False)

class Meta:
abstract = True

def save(self, *args, **kwargs):
if not self.pk:
self.expire_in = timezone.now() + datetime.timedelta(seconds=token_settings.TOKEN_AGE)
self.dead_in = self.expire_in + datetime.timedelta(seconds=token_settings.MUTABLE_PERIOD)
return super(ExpiredTokenMixin, self).save(*args, **kwargs)
2 changes: 2 additions & 0 deletions drf_secure_token/admin.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from django.contrib import admin

from drf_secure_token.models import Token


@admin.register(Token)
class TokenAdmin(admin.ModelAdmin):
list_display = ('key', 'user', 'created', 'marked_for_delete')
ordering = ('-created',)
readonly_fields = ('key',)
4 changes: 2 additions & 2 deletions drf_secure_token/authentication.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from rest_framework.authentication import TokenAuthentication
from django.utils.translation import ugettext_lazy as _

from rest_framework import exceptions
from django.utils.translation import ugettext_lazy as _
from rest_framework.authentication import TokenAuthentication

from drf_secure_token.models import Token

Expand Down
2 changes: 1 addition & 1 deletion drf_secure_token/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):
Expand Down
6 changes: 3 additions & 3 deletions drf_secure_token/migrations/0002_token_expire_in.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations
import datetime
from django.db import migrations, models
from django.utils import timezone


class Migration(migrations.Migration):
Expand All @@ -15,7 +15,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='token',
name='expire_in',
field=models.DateTimeField(default=datetime.datetime.now),
field=models.DateTimeField(default=timezone.now),
preserve_default=True,
),
]
2 changes: 1 addition & 1 deletion drf_secure_token/migrations/0003_auto_20151223_0921.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations
from django.db import migrations, models


class Migration(migrations.Migration):
Expand Down
4 changes: 2 additions & 2 deletions drf_secure_token/migrations/0004_auto_20160422_0837.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
# Generated by Django 1.9.5 on 2016-04-22 08:37
from __future__ import unicode_literals

import datetime
from django.db import migrations, models
from django.utils import timezone


class Migration(migrations.Migration):
Expand All @@ -16,7 +16,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='token',
name='dead_in',
field=models.DateTimeField(default=datetime.datetime.now),
field=models.DateTimeField(default=timezone.now),
),
migrations.AddField(
model_name='token',
Expand Down
2 changes: 1 addition & 1 deletion drf_secure_token/migrations/0005_auto_20170227_1038.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):
Expand Down
2 changes: 1 addition & 1 deletion drf_secure_token/migrations/0006_auto_20170227_1945.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models
from django.conf import settings
from django.db import migrations, models
from django.utils import timezone


Expand Down
29 changes: 29 additions & 0 deletions drf_secure_token/migrations/0007_auto_20190920_1044.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Generated by Django 2.2.1 on 2019-09-20 10:44

from django.db import migrations, models
import drf_secure_token.abstract_models


class Migration(migrations.Migration):

dependencies = [
('drf_secure_token', '0006_auto_20170227_1945'),
]

operations = [
migrations.AlterField(
model_name='token',
name='dead_in',
field=models.DateTimeField(default=drf_secure_token.abstract_models.DyingTokenMixin.default_dead_time),
),
migrations.AlterField(
model_name='token',
name='expire_in',
field=models.DateTimeField(default=drf_secure_token.abstract_models.ExpiredTokenMixin.default_expire_time),
),
migrations.AlterField(
model_name='token',
name='key',
field=models.CharField(blank=True, default=drf_secure_token.abstract_models.BaseToken.generate_key, max_length=40, unique=True),
),
]
3 changes: 1 addition & 2 deletions drf_secure_token/settings.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from django.conf import settings as django_settings


DEFAULT_SETTINGS = {
'TOKEN_AGE': 0,
'UPDATE_TOKEN': not django_settings.DEBUG,
Expand All @@ -23,7 +22,7 @@ def __init__(self, settings, default_settings):

def __getattr__(self, item):
if item not in self.default_settings:
raise AttributeError("Invalid settings: '%s'" % item)
raise AttributeError("Invalid settings: '{0}'".format(item))

return getattr(self.settings, item, self.default_settings[item])

Expand Down
3 changes: 1 addition & 2 deletions drf_secure_token/tasks.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from django.utils import timezone

from celery.task import periodic_task
from celery.schedules import crontab
from celery.task import periodic_task

from drf_secure_token.models import Token
from drf_secure_token.settings import settings as token_settings


if token_settings.REMOVE_TOKENS_THROUGH_CELERY:
@periodic_task(run_every=crontab(minute=0))
def delete_old_tokens():
Expand Down
13 changes: 2 additions & 11 deletions runtests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,9 @@
import os
import sys

import django
from django.conf import settings
from django.test.utils import get_runner


if __name__ == '__main__':
os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.test_settings'
django.setup()

TestRunner = get_runner(settings)
test_runner = TestRunner()

failures = test_runner.run_tests(['tests'])
from django.core.management import execute_from_command_line

sys.exit(bool(failures))
execute_from_command_line(sys.argv[:1] + ['test'] + sys.argv[1:])
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os

from setuptools import setup

with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as readme:
Expand All @@ -9,7 +10,7 @@

setup(
name='drf-secure-token',
version='1.0.3',
version='1.0.4',
packages=['drf_secure_token', 'drf_secure_token/migrations'],
include_package_data=True,
license='BSD License',
Expand All @@ -18,7 +19,7 @@
url='',
author='Tima Akulich',
author_email='[email protected]',
install_requires=['djangorestframework', ],
install_requires=['djangorestframework'],
classifiers=[
'Environment :: Web Environment',
'Framework :: Django',
Expand Down
22 changes: 14 additions & 8 deletions tests/test_authentication.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from django.contrib.auth.models import User
from mock import patch
from django.contrib.auth import get_user_model

from rest_framework import exceptions
from rest_framework.request import Request
from rest_framework.test import APITestCase, APIRequestFactory
from rest_framework.test import APIRequestFactory, APITestCase

from mock import patch

from drf_secure_token.authentication import SecureTokenAuthentication
from drf_secure_token.models import Token
Expand All @@ -11,22 +13,26 @@
class AuthenticationTestCase(APITestCase):
@classmethod
def setUpTestData(cls):
cls.user = User.objects.create(username='test_user')
cls.user = get_user_model().objects.create(username='test_user')
cls.request_factory = APIRequestFactory()

@patch('drf_secure_token.models.Token.check_token')
def test_calling_checkers(self, mock_check_token):
token = Token.objects.create(user=self.user)
request = Request(request=self.request_factory.get('/', HTTP_AUTHORIZATION='Token %s' % token),
authenticators=[SecureTokenAuthentication()])
request = Request(
request=self.request_factory.get('/', HTTP_AUTHORIZATION='Token {0}'.format(token)),
authenticators=[SecureTokenAuthentication()],
)

self.assertEqual(request.auth, token)
self.assertEqual(request.user, self.user)
self.assertTrue(mock_check_token.called)

def test_invalid_token(self):
request = Request(request=self.request_factory.get('/', HTTP_AUTHORIZATION='Token INVALID-TOKEN'),
authenticators=[SecureTokenAuthentication()])
request = Request(
request=self.request_factory.get('/', HTTP_AUTHORIZATION='Token INVALID-TOKEN'),
authenticators=[SecureTokenAuthentication()],
)

with self.assertRaises(exceptions.AuthenticationFailed):
request._authenticate()
13 changes: 7 additions & 6 deletions tests/test_checkers.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
from datetime import timedelta

from django.contrib.auth.models import User
from django.contrib.auth import get_user_model
from django.utils import timezone

from rest_framework.test import APITestCase

from drf_secure_token.checkers import ActiveUserChecker, ExpireTokenChecker, DeadTokenChecker
from drf_secure_token.checkers import ActiveUserChecker, DeadTokenChecker, ExpireTokenChecker
from drf_secure_token.models import Token


class CheckersTestCase(APITestCase):
def test_active_user_checker(self):
user = User.objects.create(username='test_user')
user = get_user_model().objects.create(username='test_user')
token = Token.objects.create(user=user)

inactive_user = User.objects.create(username='inactive_user', is_active=False)
inactive_user = get_user_model().objects.create(username='inactive_user', is_active=False)
inactive_token = Token.objects.create(user=inactive_user)

checker = ActiveUserChecker()
Expand All @@ -22,7 +23,7 @@ def test_active_user_checker(self):
self.assertFalse(checker.check(inactive_token))

def test_expire_token_checker(self):
user = User.objects.create(username='test_user')
user = get_user_model().objects.create(username='test_user')
valid_token = Token.objects.create(user=user)
valid_token.expire_in = timezone.now() + timedelta(seconds=5)

Expand All @@ -36,7 +37,7 @@ def test_expire_token_checker(self):
self.assertFalse(Token.objects.filter(id=invalid_token.id).exists())

def test_dead_token_checker(self):
user = User.objects.create(username='test_user')
user = get_user_model().objects.create(username='test_user')
valid_token = Token.objects.create(user=user)
valid_token.dead_in = timezone.now() + timedelta(seconds=5)

Expand Down
Loading

0 comments on commit e497df6

Please sign in to comment.