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

chore(backend): force token expire #969

Merged
merged 9 commits into from
Aug 29, 2024
34 changes: 29 additions & 5 deletions backend/api/tests/views/test_views_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,27 @@

import pytest
from django.contrib.auth.models import User
from django.db.utils import IntegrityError
from django.utils import timezone
from rest_framework import status

from users.models.token import BearerToken


@pytest.mark.django_db
def test_cannot_create_non_expiring_token(authenticated_client):
authenticated_client.create_user()
user = authenticated_client.user
# create a token without expiration date
with pytest.raises(IntegrityError):
BearerToken.objects.create(user=user)


@pytest.mark.django_db
def test_delete_token(authenticated_client):
authenticated_client.create_user()
user = authenticated_client.user
token = BearerToken.objects.create(user=user)
token = BearerToken.objects.create(user=user, expires_at=timezone.now() + timedelta(days=1))

tokens_count = BearerToken.objects.count()
assert tokens_count == 1
Expand All @@ -29,8 +39,8 @@ def test_delete_token(authenticated_client):
def test_multiple_token(authenticated_client, api_client):
authenticated_client.create_user()
user = authenticated_client.user
token_1 = BearerToken.objects.create(user=user)
token_2 = BearerToken.objects.create(user=user)
token_1 = BearerToken.objects.create(user=user, expires_at=timezone.now() + timedelta(days=1))
token_2 = BearerToken.objects.create(user=user, expires_at=timezone.now() + timedelta(days=2))

tokens_count = BearerToken.objects.count()
assert tokens_count == 2
Expand Down Expand Up @@ -60,7 +70,7 @@ def test_multiple_token(authenticated_client, api_client):


@pytest.mark.django_db
def test_expiring_token(authenticated_client, api_client):
def test_expired_token(authenticated_client, api_client):
authenticated_client.create_user()
user = authenticated_client.user
# create a token that expired a day ago
Expand Down Expand Up @@ -88,7 +98,7 @@ def test_delete_token_other_user(authenticated_client):
other_user = User.objects.create(username="user-2")
other_user.set_password("p@sswr0d44")
other_user.save()
token = BearerToken.objects.create(user=other_user)
token = BearerToken.objects.create(user=other_user, expires_at=timezone.now() + timedelta(days=1))

tokens_count = BearerToken.objects.count()
assert tokens_count == 1
Expand All @@ -111,3 +121,17 @@ def test_token_creation_post(authenticated_client):

tokens_count = BearerToken.objects.count()
assert tokens_count == 1


@pytest.mark.django_db
def test_cannot_post_token_wo_expires_at(authenticated_client):
authenticated_client.create_user()
payload = {}
url = "/api-token/"
response = authenticated_client.post(url, payload)

assert response.json() == {"expires_at": ["This field is required."]}
assert response.status_code == status.HTTP_400_BAD_REQUEST
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


tokens_count = BearerToken.objects.count()
assert tokens_count == 0
25 changes: 25 additions & 0 deletions backend/users/migrations/0008_alter_bearertoken_expires_at.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Generated by Django 4.2.5 on 2024-08-14 15:28

import django.utils.timezone
from django.db import migrations
from django.db import models


def set_default_expires_at(apps, schema_editor):
BearerToken = apps.get_model("users", "BearerToken") # noqa
BearerToken.objects.filter(expires_at__isnull=True).update(expires_at=django.utils.timezone.now())


class Migration(migrations.Migration):
dependencies = [
("users", "0007_implicitbearertoken_id_and_more"),
]

operations = [
migrations.RunPython(set_default_expires_at),
migrations.AlterField(
model_name="bearertoken",
name="expires_at",
field=models.DateTimeField(),
),
]
2 changes: 1 addition & 1 deletion backend/users/models/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

class BearerToken(Token):
note = models.TextField(null=True)
expires_at = models.DateTimeField(null=True)
expires_at = models.DateTimeField(null=False, blank=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="bearer_tokens", on_delete=models.CASCADE)
id = models.UUIDField(default=uuid.uuid4, editable=False)

Expand Down
2 changes: 1 addition & 1 deletion backend/users/serializers/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@


class BearerTokenSerializer(serializers.ModelSerializer):
expires_at = serializers.DateTimeField(default_timezone=timezone.utc, allow_null=True)
expires_at = serializers.DateTimeField(default_timezone=timezone.utc, allow_null=False)
thbcmlowk marked this conversation as resolved.
Show resolved Hide resolved
created_at = serializers.DateTimeField(default_timezone=timezone.utc, source="created", read_only=True)
token = serializers.CharField(source="key", read_only=True)

Expand Down
1 change: 1 addition & 0 deletions changes/969.changed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Disable never expiring users `BearerToken`
Loading