Cleanup & fix serializer validation

This commit is contained in:
jeremystretch 2023-04-12 09:55:27 -04:00
parent e91e3932ca
commit e425746620
3 changed files with 19 additions and 37 deletions

View File

@ -584,11 +584,16 @@ Additionally, a token can be set to expire at a specific time. This can be usefu
#### Client IP Restriction
!!! note
This feature was introduced in NetBox v3.3.
Each API token can optionally be restricted by client IP address. If one or more allowed IP prefixes/addresses is defined for a token, authentication will fail for any client connecting from an IP address outside the defined range(s). This enables restricting the use a token to a specific client. (By default, any client IP address is permitted.)
#### Creating Tokens for Other Users
It is possible to provision authentication tokens for other users via the REST API. To do, so the requesting user must have the `users.grant_token` permission assigned. While all users have inherent permission to create their own tokens, this permission is required to enable the creation of tokens for other users.
![Adding the grant action to a permission](../media/admin_ui_grant_permission.png)
!!! warning "Exercise Caution"
The ability to create tokens on behalf of other users enables the requestor to access the created token. This ability is intended e.g. for the provisioning of tokens by automated services, and should be used with extreme caution to avoid a security compromise.
### Authenticating to the API
@ -657,8 +662,3 @@ Note that we are _not_ passing an existing REST API token with this request. If
"description": ""
}
```
### Granting Other Users Tokens
The REST API allows granting of tokens to other users, this is restricted by the `users.grant_token` permission. This is achieved by assigning the user (or group) a permission on the Token object and specifying the `grant` action in the admin UI as shown below.
![Adding the grant action to a permission](../media/admin_ui_grant_permission.png)

View File

@ -93,20 +93,14 @@ class TokenSerializer(ValidatedModelSerializer):
return super().to_internal_value(data)
def validate(self, data):
"""
Check that the user has permissions to grant other users a token.
"""
if grant_user := data.get('user', None):
request = self.context.get("request")
if request and hasattr(request, "user"):
user = request.user
else:
raise PermissionDenied("Unauthorized user.")
if user != grant_user and not request.user.has_perm('users.grant_token'):
raise PermissionDenied("This user does not have permission to create tokens for other users.")
# If the Token is being created on behalf of another user, enforce the grant_token permission.
request = self.context.get('request')
token_user = data.get('user')
if token_user and token_user != request.user and not request.user.has_perm('users.grant_token'):
raise PermissionDenied("This user does not have permission to create tokens for other users.")
return data
return super().validate(data)
class TokenProvisionSerializer(serializers.Serializer):

View File

@ -155,33 +155,21 @@ class TokenTest(
def test_provision_token_other_user(self):
"""
Test the behavior of the token provisioning view when invalid credentials are supplied.
Test provisioning a Token for a different User with & without the grant_token permission.
"""
self.add_permissions('users.add_token')
user2 = User.objects.create_user(username='testuser2')
data = {
'user': user2.id,
}
url = reverse('users-api:token-list')
# Attempt to create a new Token for User2 *without* the grant_token permission
response = self.client.post(url, data, format='json', **self.header)
self.assertEqual(response.status_code, 403)
def test_provision_token_permission(self):
object_type = ContentType.objects.get(app_label='users', model='token')
objectpermission = ObjectPermission(
name=f'Permission Token',
actions=['view', 'add', 'change', 'delete', 'grant'],
)
objectpermission.save()
objectpermission.object_types.add(object_type)
objectpermission.users.add(self.user)
user2 = User.objects.create_user(username='testuser2')
data = {
'user': user2.id,
}
url = reverse('users-api:token-list')
# Assign grant_token permission and successfully create a new Token for User2
self.add_permissions('users.grant_token')
response = self.client.post(url, data, format='json', **self.header)
self.assertEqual(response.status_code, 201)