Skip to content

Commit

Permalink
Merge pull request #119 from James1345/develop
Browse files Browse the repository at this point in the history
Relase 3.3.1
  • Loading branch information
belugame authored Sep 28, 2018
2 parents d528d25 + 80d6d59 commit 143094a
Show file tree
Hide file tree
Showing 12 changed files with 102 additions and 13 deletions.
8 changes: 6 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ matrix:
- python: "3.4"
env: TOX_ENVS=py34-django111,py34-django20
- python: "3.5"
env: TOX_ENVS=py35-django111,py35-django20
env: TOX_ENVS=py35-django111,py35-django20,py35-django20,py35-django21
- python: "3.6"
env: TOX_ENVS=py36-django111,py36-django20
env: TOX_ENVS=py36-django111,py36-django20,py36-django21
- python: "3.7"
env: TOX_ENVS=py37-django20,py37-django21
dist: xenial
sudo: true
script:
- tox -e $TOX_ENVS

Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
######
3.3.1
######
- Ensure compatibility with Django 2.1 up to Python 3.7

######
3.3.0
######
- **Breaking changes**: Successful authentication **ONLY** returns `Token` object by default now.
`USER_SERIALIZER` must be overridden to return more data.

######
3.2.1
######
Expand Down
7 changes: 7 additions & 0 deletions docs/changes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
#Changelog

## 3.3.1
- Ensure compatibility with Django 2.1 up to Python 3.7

## 3.3.0
- **Breaking changes**: Successful authentication **ONLY** returns `Token` object by default now.
`USER_SERIALIZER` must be overridden to return more data.

## 3.2.1
- Fix !111: Avoid knox failing if settings are not overwritten

Expand Down
16 changes: 10 additions & 6 deletions docs/views.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@ schemes. If you would like to use a different authentication scheme to the
default, you can extend this class to provide your own value for
`authentication_classes`

When it receives an authenticated request, it will return json
- `user` an object representing the user that was authenticated
- `token` the token that should be used for any token
---
When the endpoint authenticates a request, a json object will be returned
containing the `token` key along with the actual value for the key by default.

> *This is because `USER_SERIALIZER` setting is `None` by default.*
If you wish to return custom data upon successful authentication
like `first_name`, `last_name`, and `username` then the included `UserSerializer`
class can be used inside `REST_KNOX` settings by adding `knox.serializers.UserSerializer`
---

The returned `user` object is serialized using the `USER_SERIALIZER` setting.
If this setting is not changed, the default serializer returns the user's
`first_name`, `last_name` and `username`.

Obviously, if your app uses a custom user model that does not have these fields,
a custom serializer must be used.
Expand Down
5 changes: 5 additions & 0 deletions knox/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def compare_digest(a, b):
from knox.crypto import hash_token
from knox.models import AuthToken
from knox.settings import CONSTANTS, knox_settings
from knox.signals import token_expired

User = settings.AUTH_USER_MODEL

Expand Down Expand Up @@ -99,9 +100,13 @@ def _cleanup_token(self, auth_token):
if other_token.digest != auth_token.digest and other_token.expires is not None:
if other_token.expires < timezone.now():
other_token.delete()
username = other_token.user.username
token_expired.send(sender=self.__class__, username=username, source="other_token")
if auth_token.expires is not None:
if auth_token.expires < timezone.now():
username = auth_token.user.username
auth_token.delete()
token_expired.send(sender=self.__class__, username=username, source="auth_token")
return True
return False

2 changes: 1 addition & 1 deletion knox/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = (username_field, 'first_name', 'last_name',)
fields = (username_field,)
2 changes: 1 addition & 1 deletion knox/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
'SECURE_HASH_ALGORITHM': 'cryptography.hazmat.primitives.hashes.SHA512',
'AUTH_TOKEN_CHARACTER_LENGTH': 64,
'TOKEN_TTL': timedelta(hours=10),
'USER_SERIALIZER': 'knox.serializers.UserSerializer',
'USER_SERIALIZER': None,
'AUTO_REFRESH': False,
}

Expand Down
3 changes: 3 additions & 0 deletions knox/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import django.dispatch

token_expired = django.dispatch.Signal(providing_args=["username", "source"])
4 changes: 4 additions & 0 deletions knox/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ def post(self, request, format=None):
user_logged_in.send(sender=request.user.__class__, request=request, user=request.user)
UserSerializer = knox_settings.USER_SERIALIZER
context = {'request': self.request, 'format': self.format_kwarg, 'view': self}
if UserSerializer is None:
return Response(
{'token': token}
)
return Response({
'user': UserSerializer(request.user, context=context).data,
'token': token,
Expand Down
7 changes: 5 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +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.2.1',
version='3.3.1',
description='Authentication for django rest framework',
long_description=long_description,

Expand Down Expand Up @@ -44,10 +44,13 @@

# Pick your license as you wish (should match "license" above)
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
],

# What does your project relate to?
Expand Down
45 changes: 45 additions & 0 deletions tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
)

from knox.auth import TokenAuthentication
from knox.signals import token_expired
from knox.models import AuthToken
from knox.settings import CONSTANTS, knox_settings
from knox.serializers import UserSerializer

User = get_user_model()
root_url = reverse('api-root')
Expand Down Expand Up @@ -57,6 +59,34 @@ def test_login_creates_keys(self):
self.assertEqual(AuthToken.objects.count(), 5)
self.assertTrue(all(e.token_key for e in AuthToken.objects.all()))

def test_login_returns_serialized_token(self):
self.assertEqual(AuthToken.objects.count(), 0)
url = reverse('knox_login')
self.client.credentials(
HTTP_AUTHORIZATION=get_basic_auth_header(self.username, self.password)
)
response = self.client.post(url, {}, format='json')
self.assertEqual(response.status_code, 200)
self.assertEqual(knox_settings.USER_SERIALIZER, None)
self.assertIn('token', response.data)
username_field = self.user.USERNAME_FIELD
self.assertNotIn(username_field, response.data)

def test_login_returns_serialized_token_and_username_field(self):
self.assertEqual(AuthToken.objects.count(), 0)
url = reverse('knox_login')
self.client.credentials(
HTTP_AUTHORIZATION=get_basic_auth_header(self.username, self.password)
)
knox_settings.USER_SERIALIZER = UserSerializer
response = self.client.post(url, {}, format='json')
self.assertEqual(response.status_code, 200)
self.assertNotEqual(knox_settings.USER_SERIALIZER, None)
self.assertIn('token', response.data)
username_field = self.user.USERNAME_FIELD
self.assertIn('user', response.data)
self.assertIn(username_field, response.data['user'])

def test_logout_deletes_keys(self):
self.assertEqual(AuthToken.objects.count(), 0)
for _ in range(2):
Expand Down Expand Up @@ -209,3 +239,18 @@ def test_token_expiry_is_not_extended_within_MIN_REFRESH_INTERVAL(self):

self.assertEqual(response.status_code, 200)
self.assertEqual(original_expiry, AuthToken.objects.get().expires)

def test_expiry_signals(self):
self.signal_was_called = False

def handler(sender, username, **kwargs):
self.signal_was_called = True

token_expired.connect(handler)

token = AuthToken.objects.create(user=self.user, expires=timedelta(0))
self.client.credentials(HTTP_AUTHORIZATION=('Token %s' % token))
response = self.client.post(root_url, {}, format='json')

self.assertTrue(self.signal_was_called)

5 changes: 4 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
envlist =
py{27,34,35,36}-django111,
py{34,35,36}-django20,
py{35,36,37}-django21,

[testenv]
commands =
Expand All @@ -11,9 +12,11 @@ setenv =
DJANGO_SETTINGS_MODULE = knox_project.settings
PIP_INDEX_URL = https://pypi.python.org/simple/
deps =
django111: Django>=1.11,<1.12
django111: Django>=1.11,<2.0
django20: Django>=2.0,<2.1
django21: Django>=2.1,<2.2
django-nose
markdown<3.0
djangorestframework
flake8
freezegun
Expand Down

0 comments on commit 143094a

Please sign in to comment.