Skip to content
Snippets Groups Projects
Commit 166387b6 authored by Lennard Strohmeyer's avatar Lennard Strohmeyer :penguin:
Browse files

#87: added mutex to hopefully prevent rare race condition when creating a new...

#87: added mutex to hopefully prevent rare race condition when creating a new user from a shibboleth account
parent 87dff38f
No related branches found
No related tags found
No related merge requests found
......@@ -19,3 +19,6 @@ SP_HOST=
ANONYMIZATION_HASH_PREFIX=anon
ANONYMIZATION_DEFAULT_MINIMUM_COUNT=10
CACHE_BACKEND='redis'
CACHE_URI='redis://127.0.0.1:6379'
\ No newline at end of file
......@@ -18,3 +18,6 @@ SP_HOST=
ANONYMIZATION_HASH_PREFIX=anon
ANONYMIZATION_DEFAULT_MINIMUM_COUNT=10
CACHE_BACKEND='redis'
CACHE_URI='redis://127.0.0.1:6379'
\ No newline at end of file
......@@ -127,6 +127,15 @@ else:
}
}
# Cache(s)
# https://docs.djangoproject.com/en/4.1/topics/cache/
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache' if env("CACHE_BACKEND", default="file") == "redis"
else 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/tmp/django_cache' if env("CACHE_BACKEND", default="file") == 'file' else env("CACHE_URI", default='redis://127.0.0.1:6379') ,
}
}
# Password validation
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators
......
......@@ -3,7 +3,9 @@ import string
import random
import os
import secrets
import time
from django.core.cache import cache
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.http.response import JsonResponse
......@@ -392,17 +394,37 @@ class CreateUserConsentViaConnectServiceView(APIView):
user = CustomUser.objects.filter(shibboleth_connector_identifier=shib_id).first()
message = "user exists"
if not user:
lock_key = f"user_creation_lock_{shib_id}" # "mutex" to prevent race conditions using a cache entry
if cache.add(lock_key, "locked", 2): # 2 is a timeout value, after wich the cache entry is deleted
try:
user = CustomUser.objects.create(
shibboleth_connector_identifier=shib_id, # this is the pairwaise id
shibboleth_connector_identifier=shib_id, # this is the pairwise id
email=''.join(random.choices(string.ascii_uppercase + string.digits, k=8)) + "@manual-created.polaris",
first_name=''.join(random.choices(string.ascii_uppercase + string.digits, k=8)),
last_name=''.join(random.choices(string.ascii_uppercase + string.digits, k=8))
)
except Exception as e:
return JsonResponse({"message": "user could not be created"}, safe=False,
status=status.HTTP_500_INTERNAL_SERVER_ERROR)
finally:
message = "user has been created"
cache.delete(lock_key)
else:
for _ in range(4): # Wait up to 2x lock_timeout
time.sleep(0.1)
if not cache.get(lock_key):
break
# Fetch the user created by another process
user = CustomUser.objects.filter(shibboleth_connector_identifier=shib_id).first()
if not user:
return JsonResponse({"message": "user could not be created"}, safe=False,
status=status.HTTP_500_INTERNAL_SERVER_ERROR)
return JsonResponse(
{
"message": "user is created",
"message": message,
},
safe=False,
status=status.HTTP_200_OK,
......
......@@ -85,7 +85,7 @@ def shib_connector_resolver_to_pairwaise_id(email, provider):
additionalData = None
shib_id = client.service.GetOrGenerateIdAndConnect(app_secret, user_id, lrs_type, linkType, processId, additionalData)
if len(shib_id) != 1:
print("Multiple pairwaise ids found, only use the first one!")
print("Multiple pairwise ids found, only use the first one!")
shib_id = shib_id[0]
if settings.DEBUG:
print("Result shib_id: {0}".format(shib_id))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment