Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

removed token_key from AuthToken #246

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 17 additions & 21 deletions knox/auth.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
try:
from hmac import compare_digest
except ImportError:
def compare_digest(a, b):
return a == b

import binascii

from django.utils import timezone
Expand All @@ -15,7 +9,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.settings import knox_settings
from knox.signals import token_expired


Expand Down Expand Up @@ -62,20 +56,22 @@ def authenticate_credentials(self, token):
'''
msg = _('Invalid token.')
token = token.decode("utf-8")
for auth_token in AuthToken.objects.filter(
token_key=token[:CONSTANTS.TOKEN_KEY_LENGTH]):
if self._cleanup_token(auth_token):
continue

try:
digest = hash_token(token)
except (TypeError, binascii.Error):
raise exceptions.AuthenticationFailed(msg)
if compare_digest(digest, auth_token.digest):
if knox_settings.AUTO_REFRESH and auth_token.expiry:
self.renew_token(auth_token)
return self.validate_user(auth_token)
raise exceptions.AuthenticationFailed(msg)
try:
digest = hash_token(token)
except (TypeError, binascii.Error):
raise exceptions.AuthenticationFailed(msg)

try:
auth_token = AuthToken.objects.get(digest=digest)
except AuthToken.DoesNotExist:
raise exceptions.AuthenticationFailed(msg)

if self._cleanup_token(auth_token):
raise exceptions.AuthenticationFailed(msg)

if knox_settings.AUTO_REFRESH and auth_token.expiry:
self.renew_token(auth_token)
return self.validate_user(auth_token)

def renew_token(self, auth_token):
current_expiry = auth_token.expiry
Expand Down
17 changes: 17 additions & 0 deletions knox/migrations/0009_remove_authtoken_token_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 3.1.6 on 2021-02-15 23:48

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('knox', '0008_remove_authtoken_salt'),
]

operations = [
migrations.RemoveField(
model_name='authtoken',
name='token_key',
),
]
5 changes: 1 addition & 4 deletions knox/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ def create(self, user, expiry=knox_settings.TOKEN_TTL):
expiry = timezone.now() + expiry

instance = super(AuthTokenManager, self).create(
token_key=token[:CONSTANTS.TOKEN_KEY_LENGTH], digest=digest,
user=user, expiry=expiry)
digest=digest, user=user, expiry=expiry)
return instance, token


Expand All @@ -28,8 +27,6 @@ class AuthToken(models.Model):

digest = models.CharField(
max_length=CONSTANTS.DIGEST_LENGTH, primary_key=True)
token_key = models.CharField(
max_length=CONSTANTS.TOKEN_KEY_LENGTH, db_index=True)
user = models.ForeignKey(User, null=False, blank=False,
related_name='auth_token_set', on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
Expand Down
1 change: 0 additions & 1 deletion knox/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ class CONSTANTS:
'''
Constants cannot be changed at runtime
'''
TOKEN_KEY_LENGTH = 8
DIGEST_LENGTH = 128

def __setattr__(self, *args, **kwargs):
Expand Down
27 changes: 5 additions & 22 deletions tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@

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

User = get_user_model()
Expand Down Expand Up @@ -59,17 +60,6 @@ def setUp(self):
self.password2 = 'hunter2'
self.user2 = User.objects.create_user(self.username2, self.email2, self.password2)

def test_login_creates_keys(self):
self.assertEqual(AuthToken.objects.count(), 0)
url = reverse('knox_login')
self.client.credentials(
HTTP_AUTHORIZATION=get_basic_auth_header(self.username, self.password))

for _ in range(5):
self.client.post(url, {}, format='json')
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')
Expand Down Expand Up @@ -185,16 +175,16 @@ def test_expired_tokens_deleted(self):
self.client.post(url, {}, format='json')
self.assertEqual(AuthToken.objects.count(), 0)

def test_update_token_key(self):
def test_update_token_digest(self):
self.assertEqual(AuthToken.objects.count(), 0)
instance, token = AuthToken.objects.create(self.user)
rf = APIRequestFactory()
request = rf.get('/')
request.META = {'HTTP_AUTHORIZATION': 'Token {}'.format(token)}
(self.user, auth_token) = TokenAuthentication().authenticate(request)
self.assertEqual(
token[:CONSTANTS.TOKEN_KEY_LENGTH],
auth_token.token_key,
hash_token(token),
auth_token.digest,
)

def test_authorization_header_empty(self):
Expand Down Expand Up @@ -225,13 +215,6 @@ def test_authorization_header_spaces_in_token_string(self):
str(err.exception),
)

def test_invalid_token_length_returns_401_code(self):
invalid_token = "1" * (CONSTANTS.TOKEN_KEY_LENGTH - 1)
self.client.credentials(HTTP_AUTHORIZATION=('Token %s' % invalid_token))
response = self.client.post(root_url, {}, format='json')
self.assertEqual(response.status_code, 401)
self.assertEqual(response.data, {"detail": "Invalid token."})

def test_invalid_odd_length_token_returns_401_code(self):
instance, token = AuthToken.objects.create(self.user)
odd_length_token = token + '1'
Expand Down