Skip to content

Commit 5ad6bd8

Browse files
authored
Merge pull request #20577 from netbox-community/20492-disable-token-plaintext-retrieval
Closes #20492: Disable API token plaintext retrieval
2 parents b7cc4c4 + 2bebfcc commit 5ad6bd8

File tree

8 files changed

+10
-42
lines changed

8 files changed

+10
-42
lines changed

docs/configuration/security.md

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,5 @@
11
# Security & Authentication Parameters
22

3-
## ALLOW_TOKEN_RETRIEVAL
4-
5-
Default: `False`
6-
7-
!!! note
8-
The default value of this parameter changed from `True` to `False` in NetBox v4.3.0.
9-
10-
If disabled, the values of API tokens will not be displayed after each token's initial creation. A user **must** record the value of a token prior to its creation, or it will be lost. Note that this affects _all_ users, regardless of assigned permissions.
11-
12-
---
13-
143
## ALLOWED_URL_SCHEMES
154

165
!!! tip "Dynamic Configuration Parameter"

docs/integrations/rest-api.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ Likewise, the site, rack, and device objects are located under the "DCIM" applic
8080

8181
The full hierarchy of available endpoints can be viewed by navigating to the API root in a web browser.
8282

83-
Each model generally has two views associated with it: a list view and a detail view. The list view is used to retrieve a list of multiple objects and to create new objects. The detail view is used to retrieve, update, or delete an single existing object. All objects are referenced by their numeric primary key (`id`).
83+
Each model generally has two views associated with it: a list view and a detail view. The list view is used to retrieve a list of multiple objects and to create new objects. The detail view is used to retrieve, update, or delete a single existing object. All objects are referenced by their numeric primary key (`id`).
8484

8585
* `/api/dcim/devices/` - List existing devices or create a new device
8686
* `/api/dcim/devices/123/` - Retrieve, update, or delete the device with ID 123
@@ -655,6 +655,9 @@ The NetBox REST API primarily employs token-based authentication. For convenienc
655655

656656
A token is a secret, unique identifier mapped to a NetBox user account. Each user may have one or more tokens which he or she can use for authentication when making REST API requests. To create a token, navigate to the API tokens page under your user profile. When creating a token, NetBox will automatically populate a randomly-generated token value.
657657

658+
!!! note "Tokens cannot be retrieved once created"
659+
Once a token has been created, its plaintext value cannot be retrieved. For this reason, you must take care to securely record the token locally immediately upon its creation. If a token plaintext is lost, it cannot be recovered: A new token must be created.
660+
658661
By default, all users can create and manage their own REST API tokens under the user control panel in the UI or via the REST API. This ability can be disabled by overriding the [`DEFAULT_PERMISSIONS`](../configuration/security.md#default_permissions) configuration parameter.
659662

660663
Additionally, a token can be set to expire at a specific time. This can be useful if an external client needs to be granted temporary access to NetBox.
@@ -663,7 +666,7 @@ Additionally, a token can be set to expire at a specific time. This can be usefu
663666

664667
Beginning with NetBox v4.5, two versions of API token are supported, denoted as v1 and v2. Users are strongly encouraged to create only v2 tokens and to discontinue the use of v1 tokens. Support for v1 tokens will be removed in a future NetBox release.
665668

666-
v2 API tokens offer much stronger security. The token plaintext given at creation time is hashed together with a configured [cryptographic pepper](../configuration/required-parameters.md#api_token_peppers) to generate a unique checksum. This checksum is irreversible; the token plaintext is never stored on the server and thus cannot be retrieved.
669+
v2 API tokens offer much stronger security. The token plaintext given at creation time is hashed together with a configured [cryptographic pepper](../configuration/required-parameters.md#api_token_peppers) to generate a unique checksum. This checksum is irreversible; the token plaintext is never stored on the server and thus cannot be retrieved even with database-level access.
667670

668671
#### Restricting Write Operations
669672

netbox/netbox/configuration_example.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,6 @@
9191
# ('John Doe', 'jdoe@example.com'),
9292
]
9393

94-
# Permit the retrieval of API tokens after their creation.
95-
ALLOW_TOKEN_RETRIEVAL = False
96-
9794
# Enable any desired validators for local account passwords below. For a list of included validators, please see the
9895
# Django documentation at https://docs.djangoproject.com/en/stable/topics/auth/passwords/#password-validation.
9996
AUTH_PASSWORD_VALIDATORS = [

netbox/netbox/configuration_testing.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@
4343

4444
DEFAULT_PERMISSIONS = {}
4545

46-
ALLOW_TOKEN_RETRIEVAL = True
47-
4846
API_TOKEN_PEPPERS = {
4947
1: 'TEST-VALUE-DO-NOT-USE-TEST-VALUE-DO-NOT-USE-TEST-VALUE-DO-NOT-USE',
5048
}

netbox/netbox/settings.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@
7676

7777
# Set static config parameters
7878
ADMINS = getattr(configuration, 'ADMINS', [])
79-
ALLOW_TOKEN_RETRIEVAL = getattr(configuration, 'ALLOW_TOKEN_RETRIEVAL', False)
8079
ALLOWED_HOSTS = getattr(configuration, 'ALLOWED_HOSTS') # Required
8180
API_TOKEN_PEPPERS = getattr(configuration, 'API_TOKEN_PEPPERS', {})
8281
AUTH_PASSWORD_VALIDATORS = getattr(configuration, 'AUTH_PASSWORD_VALIDATORS', [

netbox/templates/users/token.html

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,7 @@ <h2 class="card-header">{% trans "Token" %}</h2>
2020
{% if object.version == 1 %}
2121
<tr>
2222
<th scope="row">{% trans "Token" %}</th>
23-
<td>
24-
{% if settings.ALLOW_TOKEN_RETRIEVAL %}
25-
<span id="secret" class="font-monospace" data-secret="{{ object.plaintext }}">{{ object.plaintext }}</span>
26-
<button type="button" class="btn btn-primary toggle-secret float-end" data-bs-toggle="button">{% trans "Show Secret" %}</button>
27-
{% else %}
28-
{{ object.partial }}
29-
{% endif %}
30-
</td>
23+
<td>{{ object.partial }}</td>
3124
</tr>
3225
{% else %}
3326
<tr>

netbox/users/forms/model_forms.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import json
22

33
from django import forms
4-
from django.conf import settings
54
from django.contrib.auth import password_validation
65
from django.contrib.postgres.forms import SimpleArrayField
76
from django.core.exceptions import FieldError
@@ -115,7 +114,7 @@ class UserTokenForm(forms.ModelForm):
115114
label=_('Token'),
116115
help_text=_(
117116
'Tokens must be at least 40 characters in length. <strong>Be sure to record your key</strong> prior to '
118-
'submitting this form, as it may no longer be accessible once the token has been created.'
117+
'submitting this form, as it will no longer be accessible once the token has been created.'
119118
),
120119
widget=forms.TextInput(
121120
attrs={'data-clipboard': 'true'}
@@ -148,11 +147,8 @@ def __init__(self, *args, **kwargs):
148147
self.fields['version'].disabled = True
149148
self.fields['user'].disabled = True
150149

151-
# Omit the key field when editing an existing token if token retrieval is not permitted
152-
if self.instance.v1 and settings.ALLOW_TOKEN_RETRIEVAL:
153-
self.initial['token'] = self.instance.plaintext
154-
else:
155-
del self.fields['token']
150+
# Omit the key field when editing an existing Token
151+
del self.fields['token']
156152

157153
# Generate an initial random key if none has been specified
158154
elif self.instance._state.adding and not self.initial.get('token'):

netbox/users/tables.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,7 @@
1111
'UserTable',
1212
)
1313

14-
TOKEN = """<samp><a href="{{ record.get_absolute_url }}" id="token_{{ record.pk }}">{{ record }}</a></samp>"""
15-
16-
COPY_BUTTON = """
17-
{% if settings.ALLOW_TOKEN_RETRIEVAL %}
18-
{% copy_content record.pk prefix="token_" color="success" %}
19-
{% endif %}
20-
"""
14+
TOKEN = """<samp><a href="{{ record.get_absolute_url }}">{{ record }}</a></samp>"""
2115

2216

2317
class TokenTable(NetBoxTable):
@@ -48,7 +42,6 @@ class TokenTable(NetBoxTable):
4842
)
4943
actions = columns.ActionsColumn(
5044
actions=('edit', 'delete'),
51-
extra_buttons=COPY_BUTTON
5245
)
5346

5447
class Meta(NetBoxTable.Meta):

0 commit comments

Comments
 (0)