File: test_model.py

package info (click to toggle)
djangorestframework-api-key 3.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 392 kB
  • sloc: python: 926; makefile: 53; sh: 3
file content (117 lines) | stat: -rw-r--r-- 3,904 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import datetime as dt
import string

import pytest
from django.contrib.auth.hashers import make_password
from django.core.exceptions import ValidationError
from django.db.utils import IntegrityError
from test_project.heroes.models import Hero, HeroAPIKey

from rest_framework_api_key.models import APIKey

from .dateutils import NOW, TOMORROW, YESTERDAY

pytestmark = pytest.mark.django_db


def test_key_generation() -> None:
    api_key, generated_key = APIKey.objects.create_key(name="test")
    prefix = api_key.prefix
    hashed_key = api_key.hashed_key

    assert prefix and hashed_key

    charset = set(string.ascii_letters + string.digits + ".")
    assert all(c in charset for c in generated_key)

    # The generated key must be valid…
    assert api_key.is_valid(generated_key) is True

    # But not the hashed key.
    assert api_key.is_valid(hashed_key) is False


def test_name_is_required() -> None:
    with pytest.raises(IntegrityError):
        APIKey.objects.create()


def test_cannot_unrevoke() -> None:
    api_key, _ = APIKey.objects.create_key(name="test", revoked=True)

    # Try to unrevoke the API key programmatically.
    api_key.revoked = False

    with pytest.raises(ValidationError):
        api_key.save()

    with pytest.raises(ValidationError):
        api_key.clean()


@pytest.mark.parametrize(
    "expiry_date, has_expired",
    [(None, False), (NOW, True), (TOMORROW, False), (YESTERDAY, True)],
)
def test_has_expired(expiry_date: dt.datetime, has_expired: bool) -> None:
    api_key, _ = APIKey.objects.create_key(name="test", expiry_date=expiry_date)
    assert api_key.has_expired is has_expired


def test_custom_api_key_model() -> None:
    hero = Hero.objects.create()
    hero_api_key, generated_key = HeroAPIKey.objects.create_key(name="test", hero=hero)
    assert hero_api_key.is_valid(generated_key)
    assert hero_api_key.hero.id == hero.id
    assert hero.api_keys.first() == hero_api_key


@pytest.mark.django_db
def test_api_key_hash_upgrade() -> None:
    """Tests the hashing algo upgrade from Django's PW hashers to sha512."""
    key_generator = APIKey.objects.key_generator

    api_key, generated_key = APIKey.objects.create_key(name="test")
    assert api_key.is_valid(generated_key)
    assert key_generator.using_preferred_hasher(api_key.hashed_key)

    # Use Django's built-in hashers, the old way of storing a key
    api_key.hashed_key = make_password(generated_key)
    api_key.save()

    # Simple sanity check to ensure the hash is still being checked
    # and that we aren't using the preferred hasher (using Django's slower hashers)
    assert not api_key.is_valid(key_generator.hash("invalid-key"))
    assert not key_generator.using_preferred_hasher(api_key.hashed_key)

    # After calling `is_valid`, the key has been upgraded to use the preferred hasher
    assert api_key.is_valid(generated_key)
    assert key_generator.using_preferred_hasher(api_key.hashed_key)


@pytest.mark.django_db
def test_api_key_manager_get_from_key() -> None:
    api_key, generated_key = APIKey.objects.create_key(name="test")
    retrieved_key = APIKey.objects.get_from_key(generated_key)
    assert retrieved_key == api_key


@pytest.mark.django_db
def test_api_key_manager_get_from_key_missing_key() -> None:
    with pytest.raises(APIKey.DoesNotExist):
        APIKey.objects.get_from_key("foobar")


@pytest.mark.django_db
def test_api_key_manager_get_from_key_invalid_key() -> None:
    api_key, generated_key = APIKey.objects.create_key(name="test")
    prefix, _, _ = generated_key.partition(".")
    invalid_key = f"{prefix}.foobar"
    with pytest.raises(APIKey.DoesNotExist):
        APIKey.objects.get_from_key(invalid_key)


def test_api_key_str() -> None:
    _, generated_key = APIKey.objects.create_key(name="test")
    retrieved_key = APIKey.objects.get_from_key(generated_key)
    assert str(retrieved_key) == "test"