Merge branch 'configurable_backend' into 'master'
Ajoute un hook pour choisir le username des users générés See merge request klub-dev-ens/authens!2
This commit is contained in:
commit
9880015561
5 changed files with 90 additions and 16 deletions
|
@ -30,21 +30,6 @@ def get_entrance_year(attributes):
|
||||||
return 2000 + year
|
return 2000 + year
|
||||||
|
|
||||||
|
|
||||||
def find_available_username(clipper_uid):
|
|
||||||
"""Find an available username 'close' to a clipper uid."""
|
|
||||||
|
|
||||||
taken = UserModel.objects.filter(username__startswith=clipper_uid).values_list(
|
|
||||||
"username", flat=True
|
|
||||||
)
|
|
||||||
if clipper_uid not in taken:
|
|
||||||
return clipper_uid
|
|
||||||
else:
|
|
||||||
i = 2
|
|
||||||
while clipper_uid + str(i) in taken:
|
|
||||||
i += 1
|
|
||||||
return clipper_uid + str(i)
|
|
||||||
|
|
||||||
|
|
||||||
class ENSCASBackend:
|
class ENSCASBackend:
|
||||||
"""ENSAuth authentication backend.
|
"""ENSAuth authentication backend.
|
||||||
|
|
||||||
|
@ -72,6 +57,31 @@ class ENSCASBackend:
|
||||||
year = get_entrance_year(attributes)
|
year = get_entrance_year(attributes)
|
||||||
return self._get_or_create(uid, year)
|
return self._get_or_create(uid, year)
|
||||||
|
|
||||||
|
def get_free_username(self, clipper_uid):
|
||||||
|
"""Find an available username for the new user.
|
||||||
|
|
||||||
|
If you override this method, make sure it returns a username that is not taken
|
||||||
|
by any existing user.
|
||||||
|
This method will be called from within an atomic database transation (don't
|
||||||
|
worry about data races).
|
||||||
|
"""
|
||||||
|
|
||||||
|
taken = UserModel.objects.values_list("username", flat=True)
|
||||||
|
|
||||||
|
# This should handle most cases and produce a nice username.
|
||||||
|
prefered = [clipper_uid, "cas_" + clipper_uid]
|
||||||
|
pref_taken = taken.filter(username__in=prefered)
|
||||||
|
for name in prefered:
|
||||||
|
if name not in pref_taken:
|
||||||
|
return name
|
||||||
|
|
||||||
|
# Worst case: generate a username of the form clipper_uid + int
|
||||||
|
taken = taken.filter(username__startswith=clipper_uid)
|
||||||
|
i = 2
|
||||||
|
while clipper_uid + str(i) in taken:
|
||||||
|
i += 1
|
||||||
|
return clipper_uid + str(i)
|
||||||
|
|
||||||
def _get_or_create(self, uid, entrance_year):
|
def _get_or_create(self, uid, entrance_year):
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
try:
|
try:
|
||||||
|
@ -83,7 +93,7 @@ class ENSCASBackend:
|
||||||
user = None
|
user = None
|
||||||
|
|
||||||
if user is None:
|
if user is None:
|
||||||
username = find_available_username(uid)
|
username = self.get_free_username(uid)
|
||||||
user = UserModel.objects.create_user(username=username)
|
user = UserModel.objects.create_user(username=username)
|
||||||
Clipper.objects.create(user=user, entrance_year=entrance_year, uid=uid)
|
Clipper.objects.create(user=user, entrance_year=entrance_year, uid=uid)
|
||||||
return user
|
return user
|
||||||
|
|
0
authens/tests/__init__.py
Normal file
0
authens/tests/__init__.py
Normal file
25
authens/tests/test_backend.py
Normal file
25
authens/tests/test_backend.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from authens.backends import ENSCASBackend
|
||||||
|
|
||||||
|
UserModel = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
|
class TestBackend(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
UserModel.objects.create(username="toto")
|
||||||
|
UserModel.objects.create(username="toto2")
|
||||||
|
|
||||||
|
def test_usernames_uniqueness(self):
|
||||||
|
backend = ENSCASBackend()
|
||||||
|
for _ in range(10):
|
||||||
|
username = backend.get_free_username("toto")
|
||||||
|
self.assertFalse(UserModel.objects.filter(username=username).exists())
|
||||||
|
UserModel.objects.create(username=username)
|
||||||
|
for _ in range(10):
|
||||||
|
username = backend.get_free_username("tutu")
|
||||||
|
self.assertFalse(UserModel.objects.filter(username=username).exists())
|
||||||
|
UserModel.objects.create(username=username)
|
||||||
|
|
||||||
|
# TODO: https://git.eleves.ens.fr/klub-dev-ens/authens/issues/4
|
17
runtests.py
Normal file
17
runtests.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# Source:
|
||||||
|
# https://docs.djangoproject.com/en/3.0/topics/testing/advanced/#using-the-django-test-runner-to-test-reusable-applications
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import django
|
||||||
|
from django.conf import settings
|
||||||
|
from django.test.utils import get_runner
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.settings'
|
||||||
|
django.setup()
|
||||||
|
TestRunner = get_runner(settings)
|
||||||
|
test_runner = TestRunner()
|
||||||
|
failures = test_runner.run_tests(sys.argv[1:])
|
||||||
|
sys.exit(bool(failures))
|
22
tests/settings.py
Normal file
22
tests/settings.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
from django.urls import reverse_lazy # noqa
|
||||||
|
|
||||||
|
# Minimal settings to run a django app using authens.
|
||||||
|
|
||||||
|
|
||||||
|
SECRET_KEY = "dummy"
|
||||||
|
|
||||||
|
INSTALLED_APPS = [
|
||||||
|
"django.contrib.contenttypes",
|
||||||
|
"django.contrib.auth",
|
||||||
|
"authens",
|
||||||
|
"tests",
|
||||||
|
]
|
||||||
|
|
||||||
|
AUTHENTICATION_BACKENDS = [
|
||||||
|
"django.contrib.auth.backends.ModelBackend",
|
||||||
|
"authens.backends.ENSCASBackend",
|
||||||
|
]
|
||||||
|
|
||||||
|
DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3"}}
|
||||||
|
|
||||||
|
LOGIN_URL = reverse_lazy("authens:login")
|
Loading…
Reference in a new issue