From c16a9567b5e4becd883a55bc628176de425fb77b Mon Sep 17 00:00:00 2001
From: Kenzo-Hugo Hillion <kenzo-hugo.hillion1@pasteur.fr>
Date: Wed, 19 Jun 2019 14:03:40 +0200
Subject: [PATCH] add JWT auth

---
 .gitlab-ci.yml                                |  4 +--
 backend/metagenedb/apps/accounts/__init__.py  |  0
 backend/metagenedb/apps/accounts/apps.py      |  5 ++++
 .../apps/accounts/migrations/__init__.py      |  0
 backend/metagenedb/apps/accounts/urls.py      | 25 +++++++++++++++++
 backend/metagenedb/settings/django.py         | 15 ++++++++++
 backend/metagenedb/tests/__init__.py          |  0
 backend/metagenedb/tests/apps/__init__.py     |  0
 .../tests/apps/accounts/__init__.py           |  0
 .../metagenedb/tests/apps/accounts/tests.py   | 28 +++++++++++++++++++
 backend/metagenedb/tests/test_user.py         | 14 ----------
 backend/metagenedb/urls.py                    |  1 +
 backend/pytest.ini                            |  2 +-
 backend/requirements.txt                      |  3 ++
 backend/requirements_dev.txt                  |  1 -
 15 files changed, 80 insertions(+), 18 deletions(-)
 create mode 100644 backend/metagenedb/apps/accounts/__init__.py
 create mode 100644 backend/metagenedb/apps/accounts/apps.py
 create mode 100644 backend/metagenedb/apps/accounts/migrations/__init__.py
 create mode 100644 backend/metagenedb/apps/accounts/urls.py
 create mode 100644 backend/metagenedb/tests/__init__.py
 create mode 100644 backend/metagenedb/tests/apps/__init__.py
 create mode 100644 backend/metagenedb/tests/apps/accounts/__init__.py
 create mode 100644 backend/metagenedb/tests/apps/accounts/tests.py
 delete mode 100644 backend/metagenedb/tests/test_user.py

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2664f9c..8c885e5 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -30,5 +30,5 @@ test-backend:
     DJANGO_SETTINGS_MODULE: "metagenedb.settings-gitlab-ci"
   script:
     - flake8 --max-line-length 120
-    - pytest --cov . 2>&1 pytest_tmp.out
-    - pytest --cov scripts/ --cov-append
+    - coverage run --source='.' scripts/manage.py test metagenedb/tests
+    - coverage report
diff --git a/backend/metagenedb/apps/accounts/__init__.py b/backend/metagenedb/apps/accounts/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/backend/metagenedb/apps/accounts/apps.py b/backend/metagenedb/apps/accounts/apps.py
new file mode 100644
index 0000000..9b3fc5a
--- /dev/null
+++ b/backend/metagenedb/apps/accounts/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class AccountsConfig(AppConfig):
+    name = 'accounts'
diff --git a/backend/metagenedb/apps/accounts/migrations/__init__.py b/backend/metagenedb/apps/accounts/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/backend/metagenedb/apps/accounts/urls.py b/backend/metagenedb/apps/accounts/urls.py
new file mode 100644
index 0000000..4d63e5a
--- /dev/null
+++ b/backend/metagenedb/apps/accounts/urls.py
@@ -0,0 +1,25 @@
+from django.urls import re_path
+from rest_framework_jwt.views import (
+    obtain_jwt_token,
+    refresh_jwt_token,
+    verify_jwt_token,
+)
+
+
+urlpatterns = [
+    re_path(
+        r'^auth/obtain_token/',
+        obtain_jwt_token,
+        name='api-jwt-auth'
+    ),
+    re_path(
+        r'^auth/refresh_token/',
+        refresh_jwt_token,
+        name='api-jwt-refresh'
+    ),
+    re_path(
+        r'^auth/verify_token/',
+        verify_jwt_token,
+        name='api-jwt-verify'
+    ),
+]
diff --git a/backend/metagenedb/settings/django.py b/backend/metagenedb/settings/django.py
index 60e4ae3..23d7982 100644
--- a/backend/metagenedb/settings/django.py
+++ b/backend/metagenedb/settings/django.py
@@ -10,6 +10,7 @@ environ.Env.read_env(root('.env'))  # reading .env file
 
 INSTALLED_APPS = [
     'metagenedb.apps.catalog',
+    'metagenedb.apps.accounts',
     'django.contrib.admin',
     'django.contrib.auth',
     'django.contrib.contenttypes',
@@ -93,6 +94,20 @@ CORS_ORIGIN_WHITELIST = (
 )
 
 
+# Rest framework
+
+REST_FRAMEWORK = {
+    'DEFAULT_PERMISSION_CLASSES': (
+        'rest_framework.permissions.IsAuthenticated',
+    ),
+    'DEFAULT_AUTHENTICATION_CLASSES': (
+        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
+        'rest_framework.authentication.SessionAuthentication',
+        'rest_framework.authentication.BasicAuthentication',
+    ),
+}
+
+
 # Config by .env file
 
 DEBUG = env.bool('DEBUG', default=False)
diff --git a/backend/metagenedb/tests/__init__.py b/backend/metagenedb/tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/backend/metagenedb/tests/apps/__init__.py b/backend/metagenedb/tests/apps/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/backend/metagenedb/tests/apps/accounts/__init__.py b/backend/metagenedb/tests/apps/accounts/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/backend/metagenedb/tests/apps/accounts/tests.py b/backend/metagenedb/tests/apps/accounts/tests.py
new file mode 100644
index 0000000..fc240e3
--- /dev/null
+++ b/backend/metagenedb/tests/apps/accounts/tests.py
@@ -0,0 +1,28 @@
+from django.urls import reverse
+from rest_framework.test import APITestCase
+from rest_framework import status
+
+
+from django.contrib.auth.models import User
+
+
+class TestAccounts(APITestCase):
+
+    def test_obtain_jwt(self):
+
+        # create an inactive user
+        url = reverse('api-jwt-auth')
+        u = User.objects.create_user(username='user', email='user@foo.com', password='pass')
+        u.is_active = False
+        u.save()
+
+        # authenticate with username and password
+        resp = self.client.post(url, {'email': 'user@foo.com', 'password': 'pass'}, format='json')
+        self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
+
+        # set the user to activate and attempt to get a token from login
+        u.is_active = True
+        u.save()
+        resp = self.client.post(url, {'username': 'user', 'password': 'pass'}, format='json')
+        self.assertEqual(resp.status_code, status.HTTP_200_OK)
+        self.assertTrue('token' in resp.data)
diff --git a/backend/metagenedb/tests/test_user.py b/backend/metagenedb/tests/test_user.py
deleted file mode 100644
index 272cf7d..0000000
--- a/backend/metagenedb/tests/test_user.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from django.contrib.auth.models import User
-from django.test import TestCase
-
-
-class TestDatabase(TestCase):
-    def test_create_user(self):
-        user = User.objects.create_user(
-            username='user',
-            email='user@foo.com',
-            password='pass'
-        )
-        user.save()
-        user_count = User.objects.all().count()
-        self.assertEqual(user_count, 1)
diff --git a/backend/metagenedb/urls.py b/backend/metagenedb/urls.py
index be868ef..88c0e52 100644
--- a/backend/metagenedb/urls.py
+++ b/backend/metagenedb/urls.py
@@ -18,6 +18,7 @@ from django.urls import include, path
 
 
 urlpatterns = [
+    path('', include('metagenedb.apps.accounts.urls')),
     path('admin/', admin.site.urls),
     path('catalog/', include('metagenedb.apps.catalog.urls'))
 ]
diff --git a/backend/pytest.ini b/backend/pytest.ini
index f150109..64eee8a 100644
--- a/backend/pytest.ini
+++ b/backend/pytest.ini
@@ -1,3 +1,3 @@
 [pytest]
-DJANGO_SETTINGS_MODULE = backend.settings
+DJANGO_SETTINGS_MODULE = metagenedb.settings
 python_files = tests.py test_*.py *_tests.py
\ No newline at end of file
diff --git a/backend/requirements.txt b/backend/requirements.txt
index f3042d7..1ab39b2 100644
--- a/backend/requirements.txt
+++ b/backend/requirements.txt
@@ -2,8 +2,11 @@ Django==2.2.1
 django-cors-headers==3.0.2
 django-environ==0.4.5
 django-extensions==2.1.7
+django-filter==2.1.0
 djangorestframework==3.9.4
+djangorestframework-jwt==1.11.0
 psycopg2==2.8.2
+PyJWT==1.7.1
 pytz==2019.1
 six==1.12.0
 sqlparse==0.3.0
diff --git a/backend/requirements_dev.txt b/backend/requirements_dev.txt
index dcd9565..5e56a93 100644
--- a/backend/requirements_dev.txt
+++ b/backend/requirements_dev.txt
@@ -20,7 +20,6 @@ pyflakes==2.1.1
 pyparsing==2.4.0
 pytest==4.6.3
 pytest-cov==2.7.1
-pytest-django==3.5.0
 pytz==2019.1
 six==1.12.0
 sqlparse==0.3.0
-- 
GitLab