mirror of
https://github.com/netbox-community/netbox.git
synced 2025-12-16 13:29:37 -06:00
Misc cleanup
This commit is contained in:
parent
43fc7fb58a
commit
f82f084c02
@ -29,6 +29,8 @@ class Token(models.Model):
|
|||||||
An API token used for user authentication. This extends the stock model to allow each user to have multiple tokens.
|
An API token used for user authentication. This extends the stock model to allow each user to have multiple tokens.
|
||||||
It also supports setting an expiration time and toggling write ability.
|
It also supports setting an expiration time and toggling write ability.
|
||||||
"""
|
"""
|
||||||
|
_token = None
|
||||||
|
|
||||||
version = models.PositiveSmallIntegerField(
|
version = models.PositiveSmallIntegerField(
|
||||||
verbose_name=_('version'),
|
verbose_name=_('version'),
|
||||||
choices=TokenVersionChoices,
|
choices=TokenVersionChoices,
|
||||||
@ -136,12 +138,12 @@ class Token(models.Model):
|
|||||||
def __init__(self, *args, token=None, **kwargs):
|
def __init__(self, *args, token=None, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# This stores the initial plaintext value (if given) on the creation of a new Token. If not provided, a
|
||||||
|
# random token value will be generated and assigned immediately prior to saving the Token instance.
|
||||||
self.token = token
|
self.token = token
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if self.v1:
|
return self.key if self.v2 else self.partial
|
||||||
return self.partial
|
|
||||||
return self.key
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('users:token', args=[self.pk])
|
return reverse('users:token', args=[self.pk])
|
||||||
@ -156,14 +158,19 @@ class Token(models.Model):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def partial(self):
|
def partial(self):
|
||||||
|
"""
|
||||||
|
Return a sanitized representation of a v1 token.
|
||||||
|
"""
|
||||||
return f'**********************************{self.plaintext[-6:]}' if self.plaintext else ''
|
return f'**********************************{self.plaintext[-6:]}' if self.plaintext else ''
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def token(self):
|
def token(self):
|
||||||
return getattr(self, '_token', None)
|
return self._token
|
||||||
|
|
||||||
@token.setter
|
@token.setter
|
||||||
def token(self, value):
|
def token(self, value):
|
||||||
|
if not self._state.adding:
|
||||||
|
raise ValueError("Cannot assign a new plaintext value for an existing token.")
|
||||||
self._token = value
|
self._token = value
|
||||||
if value is not None:
|
if value is not None:
|
||||||
if self.v1:
|
if self.v1:
|
||||||
@ -173,8 +180,11 @@ class Token(models.Model):
|
|||||||
self.update_digest()
|
self.update_digest()
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
if self._state.adding and self.v2 and not settings.API_TOKEN_PEPPERS:
|
if self._state.adding:
|
||||||
raise ValidationError(_("Cannot create v2 tokens: API_TOKEN_PEPPERS is not defined."))
|
if self.pepper_id is not None and self.pepper_id not in settings.API_TOKEN_PEPPERS:
|
||||||
|
raise ValidationError(_(
|
||||||
|
"Invalid pepper ID: {id}. Check configured API_TOKEN_PEPPERS."
|
||||||
|
).format(id=self.pepper_id))
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
# If creating a new Token and no token value has been specified, generate one
|
# If creating a new Token and no token value has been specified, generate one
|
||||||
@ -201,9 +211,9 @@ class Token(models.Model):
|
|||||||
"""
|
"""
|
||||||
Recalculate and save the HMAC digest using the currently defined pepper and token values.
|
Recalculate and save the HMAC digest using the currently defined pepper and token values.
|
||||||
"""
|
"""
|
||||||
self.pepper_id, pepper_value = get_current_pepper()
|
self.pepper_id, pepper = get_current_pepper()
|
||||||
self.hmac_digest = hmac.new(
|
self.hmac_digest = hmac.new(
|
||||||
pepper_value.encode('utf-8'),
|
pepper.encode('utf-8'),
|
||||||
self.token.encode('utf-8'),
|
self.token.encode('utf-8'),
|
||||||
hashlib.sha256
|
hashlib.sha256
|
||||||
).hexdigest()
|
).hexdigest()
|
||||||
@ -216,12 +226,14 @@ class Token(models.Model):
|
|||||||
|
|
||||||
def validate(self, token):
|
def validate(self, token):
|
||||||
"""
|
"""
|
||||||
Returns true if the given token value validates.
|
Validate the given plaintext against the token.
|
||||||
|
|
||||||
|
For v1 tokens, check that the given value is equal to the stored plaintext. For v2 tokens, calculate an HMAC
|
||||||
|
from the Token's pepper ID and the given plaintext value, and check whether the result matches the recorded
|
||||||
|
digest.
|
||||||
"""
|
"""
|
||||||
if self.is_expired:
|
|
||||||
return False
|
|
||||||
if self.v1:
|
if self.v1:
|
||||||
return token == self.key
|
return token == self.token
|
||||||
if self.v2:
|
if self.v2:
|
||||||
try:
|
try:
|
||||||
pepper = settings.API_TOKEN_PEPPERS[self.pepper_id]
|
pepper = settings.API_TOKEN_PEPPERS[self.pepper_id]
|
||||||
|
|||||||
@ -22,5 +22,5 @@ def get_current_pepper():
|
|||||||
"""
|
"""
|
||||||
if len(settings.API_TOKEN_PEPPERS) < 1:
|
if len(settings.API_TOKEN_PEPPERS) < 1:
|
||||||
raise ImproperlyConfigured("Must define API_TOKEN_PEPPERS to use v2 API tokens")
|
raise ImproperlyConfigured("Must define API_TOKEN_PEPPERS to use v2 API tokens")
|
||||||
newest_id = sorted(settings.API_TOKEN_PEPPERS)[-1]
|
newest_id = sorted(settings.API_TOKEN_PEPPERS.keys())[-1]
|
||||||
return newest_id, settings.API_TOKEN_PEPPERS[newest_id]
|
return newest_id, settings.API_TOKEN_PEPPERS[newest_id]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user