diff --git a/.travis.yml b/.travis.yml index 84e37cb8..7b461a05 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,24 +1,18 @@ language: python -python: -- '2.7' -- '3.3' -- '3.4' -- '3.5' - -env: -- DJANGO_VERSION=1.8 - install: -- pip install -q -r requirements/common.pip -- pip install -q -r requirements/dev-test.pip -- pip install -q -r requirements/dev-build.pip -- pip install -q -r requirements/dev-docs.pip -- pip install -q --upgrade --force-reinstall django==$DJANGO_VERSION - -before_script: -- python manage.py migrate + - pip install tox +matrix: + include: + - python: "2.7" + env: TOX_ENVS=py27-django111 + - python: "3.4" + env: TOX_ENVS=py34-django111,py34-django20 + - python: "3.5" + env: TOX_ENVS=py35-django111,py35-django20 + - python: "3.6" + env: TOX_ENVS=py36-django111,py36-django20 script: -- python manage.py test + - tox -e $TOX_ENVS deploy: provider: pypi diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5be1fcb7..29c2935e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,26 @@ +###### +3.1.0 +###### +- drop Django 1.8 support as djangorestframework did so too in v.3.7.0 +- build rest-knox on Django 1.11 and 2.0 + +###### +3.0.3 +###### +- drop using OpenSSL in favor of urandom + +###### +3.0.2 +###### +- Add context to UserSerializer +- improve docs + +###### +3.0.1 +###### +- improved docs and readme +- login response better supporting hyperlinked fields + ###### 3.0.3 ###### diff --git a/README.rst b/README.rst index 4ec83af3..3f769a58 100644 --- a/README.rst +++ b/README.rst @@ -14,7 +14,7 @@ extra effort; and to ensure that connections remain secure. Knox authentication is token based, similar to the ``TokenAuthentication`` built in to DRF. However, it overcomes some problems present in the default implementation: - + - DRF tokens are limited to one per user. This does not facilitate securely signing in from multiple devices, as the token is shared. It also requires *all* devices to be logged out if a server-side logout diff --git a/docs/changes.md b/docs/changes.md index cbcee3bf..a387f87c 100644 --- a/docs/changes.md +++ b/docs/changes.md @@ -1,5 +1,9 @@ #Changelog +## 3.1.0 +- drop Django 1.8 support as djangorestframework did so too in v.3.7.0 +- build rest-knox on Django 1.11 and 2.0 + ## 3.0.3 - drop using OpenSSL in favor of urandom diff --git a/knox/auth.py b/knox/auth.py index 8bb91607..ff01ed39 100644 --- a/knox/auth.py +++ b/knox/auth.py @@ -53,6 +53,7 @@ def authenticate_credentials(self, token): Tokens that have expired will be deleted and skipped ''' msg = _('Invalid token.') + token = token.decode("utf-8") for auth_token in AuthToken.objects.filter( token_key=token[:CONSTANTS.TOKEN_KEY_LENGTH]): for other_token in auth_token.user.auth_token_set.all(): diff --git a/knox/migrations/0001_initial.py b/knox/migrations/0001_initial.py index 5733b8e2..346513bb 100644 --- a/knox/migrations/0001_initial.py +++ b/knox/migrations/0001_initial.py @@ -17,7 +17,7 @@ class Migration(migrations.Migration): fields=[ ('key', models.CharField(max_length=64, serialize=False, primary_key=True)), ('created', models.DateTimeField(auto_now_add=True)), - ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='auth_token_set')), + ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='auth_token_set', on_delete=models.CASCADE)), ], ), ] diff --git a/knox/migrations/0002_auto_20150916_1425.py b/knox/migrations/0002_auto_20150916_1425.py index d1fc0a64..b2becea2 100644 --- a/knox/migrations/0002_auto_20150916_1425.py +++ b/knox/migrations/0002_auto_20150916_1425.py @@ -19,6 +19,6 @@ class Migration(migrations.Migration): ('digest', models.CharField(max_length=64, serialize=False, primary_key=True)), ('salt', models.CharField(max_length=16, serialize=False, unique=True)), ('created', models.DateTimeField(auto_now_add=True)), - ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='auth_token_set')), + ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='auth_token_set', on_delete=models.CASCADE)), ],) ] diff --git a/knox/models.py b/knox/models.py index ba676be8..0826d3e2 100644 --- a/knox/models.py +++ b/knox/models.py @@ -35,7 +35,7 @@ class AuthToken(models.Model): salt = models.CharField( max_length=CONSTANTS.SALT_LENGTH, unique=True) user = models.ForeignKey( - User, null=False, blank=False, related_name='auth_token_set') + User, null=False, blank=False, related_name='auth_token_set', on_delete=models.CASCADE) created = models.DateTimeField(auto_now_add=True) expires = models. DateTimeField(null=True, blank=True) diff --git a/knox_project/settings.py b/knox_project/settings.py index 6fce609a..f0378fcd 100644 --- a/knox_project/settings.py +++ b/knox_project/settings.py @@ -1,42 +1,13 @@ -""" -Django settings for knox_project project. - -Generated by 'django-admin startproject' using Django 1.8.4. - -For more information on this file, see -https://docs.djangoproject.com/en/1.8/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/1.8/ref/settings/ -""" - -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) import os BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'gcr$j^h2@d@sd(f#-ihtv6*hg7qno$otw62^*rzcf0tk2wz&sb' - -# SECURITY WARNING: don't run with debug turned on in production! DEBUG = True - ALLOWED_HOSTS = [] - - -# Application definition - INSTALLED_APPS = ( - 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', 'rest_framework', 'knox', 'django_nose', @@ -48,8 +19,6 @@ 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.security.SecurityMiddleware', ) @@ -65,7 +34,6 @@ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', ], }, }, @@ -73,10 +41,6 @@ WSGI_APPLICATION = 'knox_project.wsgi.application' - -# Database -# https://docs.djangoproject.com/en/1.8/ref/settings/#databases - DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', @@ -84,24 +48,12 @@ } } - -# Internationalization -# https://docs.djangoproject.com/en/1.8/topics/i18n/ - LANGUAGE_CODE = 'en-us' - TIME_ZONE = 'UTC' - USE_I18N = True - USE_L10N = True - USE_TZ = True - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/1.8/howto/static-files/ - STATIC_URL = '/static/' TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' diff --git a/knox_project/urls.py b/knox_project/urls.py index cc2692ee..ab70c0d9 100644 --- a/knox_project/urls.py +++ b/knox_project/urls.py @@ -1,26 +1,14 @@ -"""knox_project URL Configuration - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/1.8/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') -Including another URLconf - 1. Add an import: from blog import urls as blog_urls - 2. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls)) -""" -from django.conf.urls import include, url -from django.contrib import admin +try: + # For django >= 2.0 + from django.urls import include, path +except ImportError: + # For django < 2.0 + from django.conf.urls import include, url + path = url from .views import RootView urlpatterns = [ - url(r'^api/', include('knox.urls')), - url(r'^api/$', RootView.as_view(), name="api-root"), - url(r'^admin/', include(admin.site.urls)), - url(r'^', include(admin.site.urls)), + path(r'^api/', include('knox.urls')), + path(r'^api/$', RootView.as_view(), name="api-root"), ] diff --git a/requirements/common.pip b/requirements/common.pip deleted file mode 100644 index 15ac0f13..00000000 --- a/requirements/common.pip +++ /dev/null @@ -1,3 +0,0 @@ -django -djangorestframework -pyOpenSSL diff --git a/requirements/dev-build.pip b/requirements/dev-build.pip deleted file mode 100644 index 8f3da39f..00000000 --- a/requirements/dev-build.pip +++ /dev/null @@ -1,3 +0,0 @@ -setuptools -wheel -twine diff --git a/requirements/dev-docs.pip b/requirements/dev-docs.pip deleted file mode 100644 index 016bb16d..00000000 --- a/requirements/dev-docs.pip +++ /dev/null @@ -1 +0,0 @@ -mkdocs diff --git a/requirements/dev-test.pip b/requirements/dev-test.pip deleted file mode 100644 index 335944ae..00000000 --- a/requirements/dev-test.pip +++ /dev/null @@ -1,2 +0,0 @@ -flake8 -django-nose diff --git a/setup.py b/setup.py index 8795a62a..cc628eac 100644 --- a/setup.py +++ b/setup.py @@ -16,8 +16,7 @@ # Versions should comply with PEP440. For a discussion on single-sourcing # the version across setup.py and the project code, see # https://packaging.python.org/en/latest/single_source_version.html - version='3.0.3', - + version='3.1.0', description='Authentication for django rest framework', long_description=long_description, diff --git a/tests/tests.py b/tests/tests.py index 409aba0b..42eb6352 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -2,7 +2,14 @@ import datetime from django.contrib.auth import get_user_model -from django.core.urlresolvers import reverse + +try: + # For django >= 2.0 + from django.urls import reverse +except ImportError: + # For django < 2.0 + from django.conf.urls import reverse + from rest_framework.test import APIRequestFactory, APITestCase as TestCase from knox.auth import TokenAuthentication @@ -75,7 +82,7 @@ def test_logout_all_deletes_only_targets_keys(self): url = reverse('knox_logoutall') self.client.credentials(HTTP_AUTHORIZATION=('Token %s' % token)) self.client.post(url, {}, format='json') - self.assertEqual(AuthToken.objects.count(), 10, 'tokens from other users should not be affected by logout all') + self.assertEqual(AuthToken.objects.count(), 10, 'tokens from other users should not be affected by logout all') def test_expired_tokens_login_fails(self): self.assertEqual(AuthToken.objects.count(), 0) @@ -129,4 +136,3 @@ def test_invalid_token_length_returns_401_code(self): response = self.client.post(url, {}, format='json') self.assertEqual(response.status_code, 401) self.assertEqual(response.data, {"detail": "Invalid token."}) - diff --git a/tox.ini b/tox.ini new file mode 100644 index 00000000..f5a10fe6 --- /dev/null +++ b/tox.ini @@ -0,0 +1,24 @@ +[tox] +envlist = + py{27,34,35,36}-django111, + py{34,35,36}-django20, + +[testenv] +commands = + python manage.py migrate + python manage.py test +setenv = + DJANGO_SETTINGS_MODULE = knox_project.settings + PIP_INDEX_URL = https://pypi.python.org/simple/ +deps = + django111: Django>=1.11,<1.12 + django20: Django>=2.0,<2.1 + django-nose + djangorestframework + flake8 + mkdocs + pyOpenSSL + pytest-django + setuptools + twine + wheel