From c04b4bbbfaab83f566bdd287b4b7b3b58752da99 Mon Sep 17 00:00:00 2001 From: Pieter Lambrecht Date: Fri, 17 Jun 2022 14:45:56 +0200 Subject: [PATCH 1/7] Add last_used to Token model and update when used --- netbox/netbox/api/authentication.py | 5 +++++ netbox/users/admin/__init__.py | 2 +- .../users/migrations/0003_token_last_used.py | 18 ++++++++++++++++++ netbox/users/models.py | 4 ++++ 4 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 netbox/users/migrations/0003_token_last_used.py diff --git a/netbox/netbox/api/authentication.py b/netbox/netbox/api/authentication.py index 5e177bfcb..f40141de4 100644 --- a/netbox/netbox/api/authentication.py +++ b/netbox/netbox/api/authentication.py @@ -1,4 +1,5 @@ from django.conf import settings +from django.utils import timezone from rest_framework import authentication, exceptions from rest_framework.permissions import BasePermission, DjangoObjectPermissions, SAFE_METHODS @@ -18,6 +19,10 @@ class TokenAuthentication(authentication.TokenAuthentication): except model.DoesNotExist: raise exceptions.AuthenticationFailed("Invalid token") + # Update last used. + token.last_used = timezone.now() + token.save() + # Enforce the Token's expiration time, if one has been set. if token.is_expired: raise exceptions.AuthenticationFailed("Token expired") diff --git a/netbox/users/admin/__init__.py b/netbox/users/admin/__init__.py index 1b163ed06..320c28df2 100644 --- a/netbox/users/admin/__init__.py +++ b/netbox/users/admin/__init__.py @@ -58,7 +58,7 @@ class UserAdmin(UserAdmin_): class TokenAdmin(admin.ModelAdmin): form = forms.TokenAdminForm list_display = [ - 'key', 'user', 'created', 'expires', 'write_enabled', 'description' + 'key', 'user', 'created', 'expires', 'last_used', 'write_enabled', 'description' ] diff --git a/netbox/users/migrations/0003_token_last_used.py b/netbox/users/migrations/0003_token_last_used.py new file mode 100644 index 000000000..cc014e59c --- /dev/null +++ b/netbox/users/migrations/0003_token_last_used.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.4 on 2022-06-16 15:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0002_standardize_id_fields'), + ] + + operations = [ + migrations.AddField( + model_name='token', + name='last_used', + field=models.DateTimeField(blank=True, null=True), + ), + ] diff --git a/netbox/users/models.py b/netbox/users/models.py index 23068442e..a0055914b 100644 --- a/netbox/users/models.py +++ b/netbox/users/models.py @@ -203,6 +203,10 @@ class Token(models.Model): blank=True, null=True ) + last_used = models.DateTimeField( + blank=True, + null=True + ) key = models.CharField( max_length=40, unique=True, From 5d4575ed258e8ccfa55a14648e6b0eb688cfd8e4 Mon Sep 17 00:00:00 2001 From: Pieter Lambrecht Date: Fri, 17 Jun 2022 14:57:19 +0200 Subject: [PATCH 2/7] Only update every 60 seconds --- netbox/netbox/api/authentication.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/netbox/netbox/api/authentication.py b/netbox/netbox/api/authentication.py index f40141de4..3f223cf98 100644 --- a/netbox/netbox/api/authentication.py +++ b/netbox/netbox/api/authentication.py @@ -19,9 +19,11 @@ class TokenAuthentication(authentication.TokenAuthentication): except model.DoesNotExist: raise exceptions.AuthenticationFailed("Invalid token") - # Update last used. - token.last_used = timezone.now() - token.save() + # Update last used, but only once a minute. This reduces the write load on the db + timediff = timezone.now() - token.last_used + if timediff.total_seconds() > 60: + token.last_used = timezone.now() + token.save() # Enforce the Token's expiration time, if one has been set. if token.is_expired: From 5d868168a51e2a5864352c8518798eebe12d98ba Mon Sep 17 00:00:00 2001 From: Pieter Lambrecht Date: Fri, 17 Jun 2022 14:58:20 +0200 Subject: [PATCH 3/7] Rename timediff to lasted_used_diff --- netbox/netbox/api/authentication.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netbox/netbox/api/authentication.py b/netbox/netbox/api/authentication.py index 3f223cf98..fce9036aa 100644 --- a/netbox/netbox/api/authentication.py +++ b/netbox/netbox/api/authentication.py @@ -20,8 +20,8 @@ class TokenAuthentication(authentication.TokenAuthentication): raise exceptions.AuthenticationFailed("Invalid token") # Update last used, but only once a minute. This reduces the write load on the db - timediff = timezone.now() - token.last_used - if timediff.total_seconds() > 60: + last_used_diff = timezone.now() - token.last_used + if last_used_diff.total_seconds() > 60: token.last_used = timezone.now() token.save() From d32bbd06cf4ee86392724cdf4f3b66b05d2d96df Mon Sep 17 00:00:00 2001 From: Pieter Lambrecht Date: Fri, 17 Jun 2022 15:52:12 +0200 Subject: [PATCH 4/7] Fix last_used=None error --- netbox/netbox/api/authentication.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/netbox/netbox/api/authentication.py b/netbox/netbox/api/authentication.py index fce9036aa..39008f366 100644 --- a/netbox/netbox/api/authentication.py +++ b/netbox/netbox/api/authentication.py @@ -20,8 +20,7 @@ class TokenAuthentication(authentication.TokenAuthentication): raise exceptions.AuthenticationFailed("Invalid token") # Update last used, but only once a minute. This reduces the write load on the db - last_used_diff = timezone.now() - token.last_used - if last_used_diff.total_seconds() > 60: + if not token.last_used or (timezone.now() - token.last_used).total_seconds() > 60: token.last_used = timezone.now() token.save() From f8221340af52b776e6dd972897bc6d491cb0775a Mon Sep 17 00:00:00 2001 From: Pieter Lambrecht Date: Sun, 19 Jun 2022 12:40:52 +0200 Subject: [PATCH 5/7] Disable token last_used update when in Maint mode --- netbox/netbox/api/authentication.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/netbox/netbox/api/authentication.py b/netbox/netbox/api/authentication.py index 39008f366..e98376899 100644 --- a/netbox/netbox/api/authentication.py +++ b/netbox/netbox/api/authentication.py @@ -1,8 +1,11 @@ +import logging + from django.conf import settings from django.utils import timezone from rest_framework import authentication, exceptions from rest_framework.permissions import BasePermission, DjangoObjectPermissions, SAFE_METHODS +from netbox.config import get_config from users.models import Token @@ -20,9 +23,15 @@ class TokenAuthentication(authentication.TokenAuthentication): raise exceptions.AuthenticationFailed("Invalid token") # Update last used, but only once a minute. This reduces the write load on the db - if not token.last_used or (timezone.now() - token.last_used).total_seconds() > 60: - token.last_used = timezone.now() - token.save() + if not token.last_used or (timezone.now() - token.last_used).total_seconds() > 6: + # If maintenance mode is enabled, assume the database is read-only, and disable updating the token's + # last_used time upon authentication. + if get_config().MAINTENANCE_MODE: + logger = logging.getLogger('netbox.auth.login') + logger.warning("Maintenance mode enabled: disabling update of token's last used timestamp") + else: + token.last_used = timezone.now() + token.save() # Enforce the Token's expiration time, if one has been set. if token.is_expired: From ae342a0506c627e3b23196ce49940b60b94f54f5 Mon Sep 17 00:00:00 2001 From: Pieter Lambrecht Date: Sun, 19 Jun 2022 12:41:44 +0200 Subject: [PATCH 6/7] Correct delay time from 6 to 60 seconds --- netbox/netbox/api/authentication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/netbox/api/authentication.py b/netbox/netbox/api/authentication.py index e98376899..847bcbfd9 100644 --- a/netbox/netbox/api/authentication.py +++ b/netbox/netbox/api/authentication.py @@ -23,7 +23,7 @@ class TokenAuthentication(authentication.TokenAuthentication): raise exceptions.AuthenticationFailed("Invalid token") # Update last used, but only once a minute. This reduces the write load on the db - if not token.last_used or (timezone.now() - token.last_used).total_seconds() > 6: + if not token.last_used or (timezone.now() - token.last_used).total_seconds() > 60: # If maintenance mode is enabled, assume the database is read-only, and disable updating the token's # last_used time upon authentication. if get_config().MAINTENANCE_MODE: From 81cea9b9d9b86b945052d58c83341e189a58abb3 Mon Sep 17 00:00:00 2001 From: Pieter Lambrecht Date: Sun, 19 Jun 2022 13:03:03 +0200 Subject: [PATCH 7/7] Show LastUsed in /user/api-tokens/ --- netbox/templates/users/api_tokens.html | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/netbox/templates/users/api_tokens.html b/netbox/templates/users/api_tokens.html index 01ffec23a..a019cbd1f 100644 --- a/netbox/templates/users/api_tokens.html +++ b/netbox/templates/users/api_tokens.html @@ -22,11 +22,11 @@
-
+
Created
{{ token.created|annotated_date }}
-
+
Expires
{% if token.expires %} {{ token.expires|annotated_date }} @@ -34,7 +34,15 @@ Never {% endif %}
-
+
+ Last Used
+ {% if token.last_used %} + {{ token.last_used|annotated_date }} + {% else %} + Never + {% endif %} +
+
Create/Edit/Delete Operations
{% if token.write_enabled %} Enabled