Files
centurion_erp/app/api/tests/unit/token/test_token.py

330 lines
7.6 KiB
Python

import django
import hashlib
import json
from datetime import datetime, timedelta
from django.shortcuts import reverse
from django.test import TestCase, Client
from access.models.tenant import Tenant as Organization
from api.models.tokens import AuthToken
from settings.models.user_settings import UserSettings
User = django.contrib.auth.get_user_model()
class APIAuthToken(TestCase):
@classmethod
def setUpTestData(self):
"""Setup Test
1. Create an organization for user
3. create user
4. create user settings
5. create API key (valid)
6. generate an API key that does not exist
5. create API key (expired)
"""
organization = Organization.objects.create(name='test_org')
self.organization = organization
self.add_user = User.objects.create_user(username="test_user_add", password="password")
add_user_settings = UserSettings.objects.get(user=self.add_user)
add_user_settings.default_organization = organization
add_user_settings.save()
expires = datetime.utcnow() + timedelta(days = 10)
expires = expires.strftime('%Y-%m-%d %H:%M:%S%z')
token = AuthToken.objects.create(
user = self.add_user,
expires=expires
)
self.api_token_valid = token.generate
self.hashed_token = token.token_hash(self.api_token_valid)
token.token = self.hashed_token
token.save()
self.token = token
self.api_token_does_not_exist = hashlib.sha256(str('a random string').encode('utf-8')).hexdigest()
expires = datetime.utcnow() + timedelta(days = -10)
expires = expires.strftime('%Y-%m-%d %H:%M:%S%z')
self.api_token_expired = token.generate
self.hashed_token_expired = token.token_hash(self.api_token_expired)
token = AuthToken.objects.create(
user = self.add_user,
expires=expires,
token = self.hashed_token_expired
)
def test_token_create_own(self):
""" Check correct permission for add
User can only create token for self.
"""
client = Client()
client.force_login(self.add_user)
url = reverse('_user_auth_token_add', kwargs={'user_id': self.add_user.id})
response = client.post(url)
assert response.status_code == 200
def test_token_create_other_user(self):
""" Check correct permission for add
User can not create token for another user.
"""
client = Client()
client.force_login(self.add_user)
url = reverse('_user_auth_token_add', kwargs={'user_id': 999})
response = client.post(url)
assert response.status_code == 403
def test_token_delete_own(self):
""" Check correct permission for delete
User can only delete token for self.
"""
client = Client()
client.force_login(self.add_user)
url = reverse('_user_auth_token_delete', kwargs={'user_id': self.add_user.id, 'pk': self.token.id})
response = client.post(url)
assert response.status_code == 302 and response.url == '/account/settings/' + str(self.add_user.id)
def test_token_delete_other_user(self):
""" Check correct permission for delete
User can not delete another users token.
"""
client = Client()
client.force_login(self.add_user)
url = reverse('_user_auth_token_delete', kwargs={'user_id': 999, 'pk': self.token.id})
response = client.post(url, data={'id': 1})
assert response.status_code == 403
def test_auth_invalid_token(self):
""" Check token authentication
Invalid token does not allow login
"""
client = Client()
url = reverse('home') + 'api/'
response = client.get(
url,
content_type='application/json',
headers = {
'Accept': 'application/json',
'Authorization': 'Token ' + self.api_token_does_not_exist,
}
)
assert response.status_code == 401
def test_auth_no_token(self):
""" Check token authentication
providing no token does not allow login
"""
client = Client()
url = reverse('home') + 'api/'
response = client.get(
url,
content_type='application/json',
headers = {
'Accept': 'application/json'
}
)
assert response.status_code == 401
def test_auth_expired_token(self):
""" Check token authentication
expired token does not allow login
"""
client = Client()
url = reverse('home') + 'api/'
response = client.get(
url,
content_type='application/json',
headers = {
'Accept': 'application/json',
'Authorization': 'Token ' + self.api_token_expired,
}
)
assert response.status_code == 401
def test_auth_valid_token(self):
""" Check token authentication
Valid token allows login
"""
client = Client()
url = reverse('home') + 'api/'
response = client.get(
url,
content_type='application/json',
headers = {
'Accept': 'application/json',
'Authorization': 'Token ' + self.api_token_valid,
}
)
assert response.status_code == 200
def test_feat_expired_token_is_removed(self):
""" token feature confirmation
expired token is deleted
"""
client = Client()
url = reverse('home') + 'api/'
response = client.get(
url,
content_type='application/json',
headers = {
'Accept': 'application/json',
'Authorization': 'Token ' + self.api_token_expired,
}
)
db_query = AuthToken.objects.filter(
token = self.hashed_token_expired
)
assert not db_query.exists()
def test_token_not_saved_to_db(self):
""" confirm generated token not saved to the database """
db_query = AuthToken.objects.filter(
token = self.api_token_valid
)
assert not db_query.exists()
def test_header_format_invalid_token(self):
""" token header format check
header missing 'Token' prefix reports invalid
"""
client = Client()
url = reverse('home') + 'api/'
response = client.get(
url,
content_type='application/json',
headers = {
'Accept': 'application/json',
'Authorization': '' + self.api_token_valid,
}
)
content: dict = json.loads(response.content.decode('utf-8'))
assert response.status_code == 401 and content['detail'] == 'Token header invalid'
def test_header_format_invalid_token_spaces(self):
""" token header format check
auth header with extra spaces reports invalid
"""
client = Client()
url = reverse('home') + 'api/'
response = client.get(
url,
content_type='application/json',
headers = {
'Accept': 'application/json',
'Authorization': 'Token A space ' + self.api_token_valid,
}
)
content: dict = json.loads(response.content.decode('utf-8'))
assert response.status_code == 401 and content['detail'] == 'Token header invalid. Possibly incorrectly formatted'