Skip to content

Commit f118619

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

File tree

4 files changed

+90
-1
lines changed

4 files changed

+90
-1
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-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
#
1616
"""Models for the NAV API"""
1717

18-
from datetime import datetime
18+
from datetime import datetime, timezone
1919

2020
from django.contrib.postgres.fields import HStoreField
2121
from django.db import models
@@ -66,3 +66,25 @@ def get_absolute_url(self):
6666

6767
class Meta(object):
6868
db_table = 'apitoken'
69+
70+
71+
class JWTRefreshToken(models.Model):
72+
73+
name = VarcharField(unique=True)
74+
description = models.TextField(null=True, blank=True)
75+
expires = models.DateTimeField()
76+
activates = models.DateTimeField()
77+
hash = VarcharField()
78+
79+
def __str__(self):
80+
return self.name
81+
82+
def is_active(self) -> bool:
83+
"""True if token is active. A token is considered active when
84+
`activates` is in the past and `expires` is in the future.
85+
"""
86+
now = datetime.now(tz=timezone.utc)
87+
return now >= self.activates and now < self.expires
88+
89+
class Meta(object):
90+
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)