Skip to content
Snippets Groups Projects
Commit bcfbb774 authored by Art's avatar Art :lizard:
Browse files

Prevent personal data leaks when IDP provides duplicate usernames

parent af7d32ce
Branches
Tags
No related merge requests found
from uuid import UUID from uuid import UUID, uuid4
from django.db import transaction from django.db import transaction
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
...@@ -31,15 +31,25 @@ def get_user(uuid=None, username=None): ...@@ -31,15 +31,25 @@ def get_user(uuid=None, username=None):
def get_or_create_user(uuid, username): def get_or_create_user(uuid, username):
""" """
Returns a user. Returns a user.
Is able to process many weird cases like changed username or re-created user in DS. Should be able to process a bunch of weird cases like changed username or duplicate usernames.
If it dies with an exception, with 90% probability the data state is very bad. If it dies with an exception, with 90% probability the data state is very bad.
""" """
def get_user_by_uuid(uuid, username): def free_up_username(username):
try:
other_user = get_user(username=username)
except get_user_model().DoesNotExist:
return
new_username = "{0}_OLD_{1}".format(other_user.username, uuid4())
logger.warning("Found another user with username {old_username}. Renaming {old_username} to {new_username}".format(old_username=other_user.username, new_username=new_username))
other_user.username = new_username
other_user.save()
def get_existing_user(uuid, username):
try: try:
user = get_user(uuid=uuid) user = get_user(uuid=uuid)
if user.username != username: if user.username != username:
# have to do it because users might be renamed free_up_username(username)
logger.warning("Username has changed. Renaming locally from {0} to {1}.".format(user.username, username)) logger.warning("Username has changed. Renaming locally from {0} to {1}.".format(user.username, username))
user.username = username user.username = username
user.save() user.save()
...@@ -47,23 +57,9 @@ def get_or_create_user(uuid, username): ...@@ -47,23 +57,9 @@ def get_or_create_user(uuid, username):
except models.UserMapping.DoesNotExist: except models.UserMapping.DoesNotExist:
return None return None
def get_user_by_username(uuid, username):
try:
user = get_user(username=username)
except get_user_model().DoesNotExist:
return None
try:
meta = models.UserMapping.objects.get(user=user)
logger.warning("User UUID changed. Assuming re-created in DS. Automagically fixing...")
meta.uuid = uuid
meta.save()
except models.UserMapping.DoesNotExist:
logger.error("User {username} lost their meta. Auto-fixing and hoping for the best.".format(**locals()))
models.UserMapping.objects.create(user=user, uuid=uuid)
return user
def create_user(uuid, username): def create_user(uuid, username):
_validate_username(username) _validate_username(username)
free_up_username(username)
user = get_user_model().objects.create(username=username, is_staff=False) user = get_user_model().objects.create(username=username, is_staff=False)
user.set_unusable_password() user.set_unusable_password()
user.save() user.save()
...@@ -77,12 +73,8 @@ def get_or_create_user(uuid, username): ...@@ -77,12 +73,8 @@ def get_or_create_user(uuid, username):
assert isinstance(uuid, UUID) and isinstance(username, str) assert isinstance(uuid, UUID) and isinstance(username, str)
username = username.lower() username = username.lower()
# get or create # get or create
user = get_user_by_uuid(uuid, username) # best case scenario user = get_existing_user(uuid, username) or create_user(uuid, username)
if not user: # just in case, ensure the user object complies with the security rules
user = get_user_by_username(uuid, username) # worst case scenario
if not user:
user = create_user(uuid, username) # create if not present
# sanity check
cleanup_direct_permissions(user) cleanup_direct_permissions(user)
return user return user
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment