[damned-lies/person_roken: 9/9] Implement token-based authentication




commit aec3d1520b14dc911b8bd43087824d980de43c68
Author: Claude Paroz <claude 2xlibre net>
Date:   Sun Jan 31 18:15:40 2021 +0100

    Implement token-based authentication

 common/backends.py     | 17 +++++++++++++++++
 common/middleware.py   | 15 +++++++++++++++
 damnedlies/settings.py |  1 +
 people/tests.py        |  8 ++++++++
 vertimus/forms.py      |  8 ++++++--
 5 files changed, 47 insertions(+), 2 deletions(-)
---
diff --git a/common/backends.py b/common/backends.py
new file mode 100644
index 00000000..cdf505c5
--- /dev/null
+++ b/common/backends.py
@@ -0,0 +1,17 @@
+from django.contrib.auth.backends import ModelBackend
+
+from people.models import Person
+
+
+class TokenBackend(ModelBackend):
+    def authenticate(self, request, **kwargs):
+        auth = request.META.get('HTTP_AUTHENTICATION', '').split()
+        if len(auth) != 2 or auth[0] != 'Bearer':
+            return
+        try:
+            user = Person.objects.get(auth_token=auth[1])
+        except Person.DoesNotExist:
+            return
+        else:
+            if user.is_active:
+                return user
diff --git a/common/middleware.py b/common/middleware.py
new file mode 100644
index 00000000..7418fbf3
--- /dev/null
+++ b/common/middleware.py
@@ -0,0 +1,15 @@
+from django.contrib.auth import load_backend
+from django.utils.deprecation import MiddlewareMixin
+
+
+class TokenAuthenticationMiddleware(MiddlewareMixin):
+    backend_path = 'common.backends.TokenBackend'
+
+    def process_request(self, request):
+        if request.META.get('HTTP_AUTHENTICATION', '') and request.user.is_anonymous:
+            backend = load_backend(backend_path)
+            user = backend.authenticate(request)
+            if user:
+                user.backend = backend_path
+                request.user = user
+
diff --git a/damnedlies/settings.py b/damnedlies/settings.py
index d54c8387..bf3697bf 100644
--- a/damnedlies/settings.py
+++ b/damnedlies/settings.py
@@ -123,6 +123,7 @@ MIDDLEWARE = [
     'django.middleware.common.CommonMiddleware',
     'django.middleware.csrf.CsrfViewMiddleware',
     'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'common.middleware.TokenAuthenticationMiddleware',
     'django.contrib.messages.middleware.MessageMiddleware',
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
 ]
diff --git a/people/tests.py b/people/tests.py
index 8eb2a7eb..a4f9b53b 100644
--- a/people/tests.py
+++ b/people/tests.py
@@ -147,6 +147,14 @@ class PeopleTestCase(TestCase):
         pn.refresh_from_db()
         self.assertEqual(pn.auth_token, '')
 
+    def test_token_authentication(self):
+        pn = self._create_person(auth_token='askhdaksudakckascjbaskdaiwue')
+        response = self.client.get(
+            reverse('home'), HTTP_AUTHENTICATION='Bearer askhdaksudakckascjbaskdaiwue'
+        )
+        self.assertFalse(response.context['user'].is_anonymous)
+        self.assertEqual(response.context['user'], pn)
+
     def test_obsolete_accounts(self):
         from teams.models import Team, Role
         from stats.models import Module, Branch, Domain
diff --git a/vertimus/forms.py b/vertimus/forms.py
index f989c052..8396b982 100644
--- a/vertimus/forms.py
+++ b/vertimus/forms.py
@@ -62,6 +62,7 @@ class ActionForm(forms.Form):
     def __init__(self, current_user, state, actions, has_mailing_list, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.actions = actions
+        self.current_user = current_user
         self.fields['action'].choices = [(
             act.name,
             DisabledLabel(act.description) if isinstance(act, ActionSeparator) else act.description
@@ -93,8 +94,11 @@ class ActionForm(forms.Form):
         action_code = cleaned_data.get('action')
         if action_code is None:
             raise ValidationError(_("Invalid action. Someone probably posted another action just before 
you."))
-        elif action_code == 'CI' and not cleaned_data['author']:
-            raise ValidationError(_("Committing a file requires a commit author."))
+        elif action_code == 'CI':
+            if not cleaned_data['author']:
+                raise ValidationError(_("Committing a file requires a commit author."))
+            if 'Token' in getattr(self.current_user, 'backend', ''):
+                raise ValidationError(_("Committing a file with token-based authentication is prohibited."))
         comment = cleaned_data.get('comment')
         file = cleaned_data.get('file')
         action = Action.new_by_name(action_code, comment=comment, file=file)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]