Closes #2479: Add user permissions for creating/modifying API tokens

This commit is contained in:
Jeremy Stretch 2018-10-05 11:06:59 -04:00
parent 2fee977b4c
commit 5d10d8418e
6 changed files with 46 additions and 10 deletions

View File

@ -2,6 +2,7 @@ v2.4.6 (FUTURE)
## Enhancements
* [#2479](https://github.com/digitalocean/netbox/issues/2479) - Add user permissions for creating/modifying API tokens
* [#2487](https://github.com/digitalocean/netbox/issues/2487) - Return abbreviated API output when passed `?brief=1`
## Bug Fixes

View File

@ -4,6 +4,9 @@ The NetBox API employs token-based authentication. For convenience, cookie authe
A token is a unique identifier that identifies a user to the API. Each user in NetBox may have one or more tokens which he or she can use to authenticate to the API. To create a token, navigate to the API tokens page at `/user/api-tokens/`.
!!! note
The creation and modification of API tokens can be restricted per user by an administrator. If you don't see an option to create an API token, ask an administrator to grant you access.
Each token contains a 160-bit key represented as 40 hexadecimal characters. When creating a token, you'll typically leave the key field blank so that a random key will be automatically generated. However, NetBox allows you to specify a key in case you need to restore a previously deleted token to operation.
By default, a token can be used for all operations available via the API. Deselecting the "write enabled" option will restrict API requests made with the token to read operations (e.g. GET) only.

View File

@ -10,8 +10,12 @@
<div class="panel panel-{% if token.is_expired %}danger{% else %}default{% endif %}">
<div class="panel-heading">
<div class="pull-right">
<a href="{% url 'user:token_edit' pk=token.pk %}" class="btn btn-xs btn-warning">Edit</a>
<a href="{% url 'user:token_delete' pk=token.pk %}" class="btn btn-xs btn-danger">Delete</a>
{% if perms.users.change_token %}
<a href="{% url 'user:token_edit' pk=token.pk %}" class="btn btn-xs btn-warning">Edit</a>
{% endif %}
{% if perms.users.delete_token %}
<a href="{% url 'user:token_delete' pk=token.pk %}" class="btn btn-xs btn-danger">Delete</a>
{% endif %}
</div>
<i class="fa fa-key"></i> {{ token.key }}
{% if token.is_expired %}
@ -49,10 +53,16 @@
{% empty %}
<p>You do not have any API tokens.</p>
{% endfor %}
<a href="{% url 'user:token_add' %}" class="btn btn-primary">
<span class="fa fa-plus" aria-hidden="true"></span>
Add a token
</a>
{% if perms.users.add_token %}
<a href="{% url 'user:token_add' %}" class="btn btn-primary">
<span class="fa fa-plus" aria-hidden="true"></span>
Add a token
</a>
{% else %}
<div class="alert alert-info text-center" role="alert">
You do not have permission to create new API tokens. If needed, ask an administrator to enable token creation for your account or an assigned group.
</div>
{% endif %}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,17 @@
# Generated by Django 2.0.8 on 2018-10-05 14:32
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('users', '0001_api_tokens_squashed_0002_unicode_literals'),
]
operations = [
migrations.AlterModelOptions(
name='token',
options={},
),
]

View File

@ -43,7 +43,7 @@ class Token(models.Model):
)
class Meta:
default_permissions = []
pass
def __str__(self):
# Only display the last 24 bits of the token to avoid accidental exposure.

View File

@ -3,8 +3,8 @@ from __future__ import unicode_literals
from django.contrib import messages
from django.contrib.auth import login as auth_login, logout as auth_logout, update_session_auth_hash
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponseRedirect
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.http import HttpResponseForbidden, HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils.decorators import method_decorator
@ -231,8 +231,12 @@ class TokenEditView(LoginRequiredMixin, View):
def get(self, request, pk=None):
if pk is not None:
if not request.user.has_perm('users.change_token'):
return HttpResponseForbidden()
token = get_object_or_404(Token.objects.filter(user=request.user), pk=pk)
else:
if not request.user.has_perm('users.add_token'):
return HttpResponseForbidden()
token = Token(user=request.user)
form = TokenForm(instance=token)
@ -274,7 +278,8 @@ class TokenEditView(LoginRequiredMixin, View):
})
class TokenDeleteView(LoginRequiredMixin, View):
class TokenDeleteView(PermissionRequiredMixin, View):
permission_required = 'users.delete_token'
def get(self, request, pk):