Skip to content

Commit 49c7894

Browse files
committed
Add model for JWT refresh token
1 parent dbf3893 commit 49c7894

File tree

4 files changed

+90
-0
lines changed

4 files changed

+90
-0
lines changed

changelog.d/3268.added.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add database model for JWT refresh tokens

python/nav/models/api.py

+23
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from django.contrib.postgres.fields import HStoreField
2121
from django.db import models
2222
from django.urls import reverse
23+
from django.utils import timezone
2324

2425
from nav.models.fields import VarcharField
2526
from nav.models.profiles import Account
@@ -66,3 +67,25 @@ def get_absolute_url(self):
6667

6768
class Meta(object):
6869
db_table = 'apitoken'
70+
71+
72+
class JWTRefreshToken(models.Model):
73+
74+
name = VarcharField(unique=True)
75+
description = models.TextField(null=True, blank=True)
76+
expires = models.DateTimeField()
77+
activates = models.DateTimeField()
78+
hash = VarcharField()
79+
80+
def __str__(self):
81+
return self.name
82+
83+
def is_active(self) -> bool:
84+
"""True if token is active. A token is considered active when
85+
`activates` is in the past and `expires` is in the future.
86+
"""
87+
now = timezone.now()
88+
return now >= self.activates and now < self.expires
89+
90+
class Meta(object):
91+
db_table = 'jwtrefreshtoken'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CREATE TABLE manage.JWTRefreshToken (
2+
id SERIAL PRIMARY KEY,
3+
name VARCHAR NOT NULL UNIQUE,
4+
description VARCHAR,
5+
expires TIMESTAMP NOT NULL,
6+
activates TIMESTAMP NOT NULL,
7+
hash VARCHAR NOT NULL
8+
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from datetime import datetime, timedelta, timezone
2+
3+
from nav.models.api import JWTRefreshToken
4+
5+
6+
class TestIsActive:
7+
def test_should_return_false_if_token_activates_in_the_future(self):
8+
now = datetime.now(tz=timezone.utc)
9+
token = JWTRefreshToken(
10+
name="testtoken",
11+
hash="dummyhash",
12+
expires=now + timedelta(hours=1),
13+
activates=now + timedelta(hours=1),
14+
)
15+
assert not token.is_active()
16+
17+
def test_should_return_false_if_token_expires_in_the_past(self):
18+
now = datetime.now(tz=timezone.utc)
19+
token = JWTRefreshToken(
20+
name="testtoken",
21+
hash="dummyhash",
22+
expires=now - timedelta(hours=1),
23+
activates=now - timedelta(hours=1),
24+
)
25+
assert not token.is_active()
26+
27+
def test_should_return_true_if_token_activates_in_the_past_and_expires_in_the_future(
28+
self,
29+
):
30+
now = datetime.now(tz=timezone.utc)
31+
token = JWTRefreshToken(
32+
name="testtoken",
33+
hash="dummyhash",
34+
expires=now + timedelta(hours=1),
35+
activates=now - timedelta(hours=1),
36+
)
37+
assert token.is_active()
38+
39+
def test_should_return_true_if_token_activates_now_and_expires_in_the_future(self):
40+
now = datetime.now(tz=timezone.utc)
41+
token = JWTRefreshToken(
42+
name="testtoken",
43+
hash="dummyhash",
44+
expires=now + timedelta(hours=1),
45+
activates=now,
46+
)
47+
assert token.is_active()
48+
49+
50+
def test_string_representation_should_match_name():
51+
now = datetime.now(tz=timezone.utc)
52+
token = JWTRefreshToken(
53+
name="testtoken",
54+
hash="dummyhash",
55+
expires=now + timedelta(hours=1),
56+
activates=now - timedelta(hours=1),
57+
)
58+
assert str(token) == token.name

0 commit comments

Comments
 (0)