Skip to content

Commit f93a1c4

Browse files
authoredSep 17, 2023
Remove code that updates the PK (#251)
* Remove code that updates the PK And note the internal inconsistency. * After removing the PK upgrade, testing the upgrade is easier
1 parent 3a1609f commit f93a1c4

File tree

2 files changed

+29
-5
lines changed

2 files changed

+29
-5
lines changed
 

‎src/rest_framework_api_key/models.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,11 @@ def is_valid(self, key: str) -> bool:
134134
# Transparently update the key to use the preferred hasher
135135
# if it is using an outdated hasher.
136136
if valid and not key_generator.using_preferred_hasher(self.hashed_key):
137-
new_hashed_key = key_generator.hash(key)
138-
type(self).objects.filter(prefix=self.prefix).update(
139-
id=concatenate(self.prefix, new_hashed_key),
140-
hashed_key=new_hashed_key,
141-
)
137+
# Note that since the PK includes the hashed key,
138+
# they will be internally inconsistent following this upgrade.
139+
# See: https://github.com/florimondmanca/djangorestframework-api-key/issues/128
140+
self.hashed_key = key_generator.hash(key)
141+
self.save()
142142

143143
return valid
144144

‎tests/test_model.py

+24
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import string
33

44
import pytest
5+
from django.contrib.auth.hashers import make_password
56
from django.core.exceptions import ValidationError
67
from django.db.utils import IntegrityError
78
from test_project.heroes.models import Hero, HeroAPIKey
@@ -65,6 +66,29 @@ def test_custom_api_key_model() -> None:
6566
assert hero.api_keys.first() == hero_api_key
6667

6768

69+
@pytest.mark.django_db
70+
def test_api_key_hash_upgrade() -> None:
71+
"""Tests the hashing algo upgrade from Django's PW hashers to sha512."""
72+
key_generator = APIKey.objects.key_generator
73+
74+
api_key, generated_key = APIKey.objects.create_key(name="test")
75+
assert api_key.is_valid(generated_key)
76+
assert key_generator.using_preferred_hasher(api_key.hashed_key)
77+
78+
# Use Django's built-in hashers, the old way of storing a key
79+
api_key.hashed_key = make_password(generated_key)
80+
api_key.save()
81+
82+
# Simple sanity check to ensure the hash is still being checked
83+
# and that we aren't using the preferred hasher (using Django's slower hashers)
84+
assert not api_key.is_valid(key_generator.hash("invalid-key"))
85+
assert not key_generator.using_preferred_hasher(api_key.hashed_key)
86+
87+
# After calling `is_valid`, the key has been upgraded to use the preferred hasher
88+
assert api_key.is_valid(generated_key)
89+
assert key_generator.using_preferred_hasher(api_key.hashed_key)
90+
91+
6892
@pytest.mark.django_db
6993
def test_api_key_manager_get_from_key() -> None:
7094
api_key, generated_key = APIKey.objects.create_key(name="test")

0 commit comments

Comments
 (0)