From b7725ea6272b5693925a26b25f17185cf86dfbd9 Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Wed, 7 Jun 2023 22:00:23 +0200 Subject: [PATCH] Sync up to latest version of community auth plugin This moves the subscription to user changes over to a signal, to make it cleaner and keeping us from having to carry a diff against the standard auth plugin. --- gitadmin/gitadmin/adm/apps.py | 5 +-- gitadmin/gitadmin/adm/util.py | 10 +++++- gitadmin/gitadmin/auth.py | 59 ++++++++++++++++++++--------------- 3 files changed, 45 insertions(+), 29 deletions(-) diff --git a/gitadmin/gitadmin/adm/apps.py b/gitadmin/gitadmin/adm/apps.py index 17d85c1..843aa09 100644 --- a/gitadmin/gitadmin/adm/apps.py +++ b/gitadmin/gitadmin/adm/apps.py @@ -5,7 +5,8 @@ class GitAdmAppConfig(AppConfig): name = 'gitadmin.adm' def ready(self): - from gitadmin.auth import auth_user_data_received - from gitadmin.adm.util import handle_user_data + from gitadmin.auth import auth_user_data_received, auth_user_created_from_upstream + from gitadmin.adm.util import handle_user_data, handle_user_created + auth_user_created_from_upstream.connect(handle_user_created) auth_user_data_received.connect(handle_user_data) diff --git a/gitadmin/gitadmin/adm/util.py b/gitadmin/gitadmin/adm/util.py index be5453c..79e3c33 100644 --- a/gitadmin/gitadmin/adm/util.py +++ b/gitadmin/gitadmin/adm/util.py @@ -1,7 +1,7 @@ from django.contrib.auth.models import User from django.db import connection -from gitadmin.auth import user_search, user_import +from gitadmin.auth import user_search, user_import, subscribe_to_user_changes def get_or_import_user(email): try: @@ -18,6 +18,14 @@ def get_or_import_user(email): return user_import(users[0]['u']) +# New user created from upstream +def handle_user_created(user): + try: + subscribe_to_user_changes(user.username) + except Exception as e: + print("Exception subscribing new user: %s", e) + + # Updates arriving from community authentication def handle_user_data(sender, **kwargs): user = kwargs.pop('user') diff --git a/gitadmin/gitadmin/auth.py b/gitadmin/gitadmin/auth.py index daa7eaa..8a59595 100644 --- a/gitadmin/gitadmin/auth.py +++ b/gitadmin/gitadmin/auth.py @@ -8,6 +8,8 @@ # * Make sure the view "login" from this module is used for login # * Map an url somwehere (typically /auth_receive/) to the auth_receive # view. +# * To get notified when a user is created from upstream, connect to the signal +# auth_user_created_from_upstream. # * To receive live updates (not just during login), map an url somewhere # (typically /auth_api/) to the auth_api view. # * To receive live updates, also connect to the signal auth_user_data_received. @@ -44,6 +46,9 @@ from Cryptodome import Random import time +# This signal fires when a user is created based on data from upstream. +auth_user_created_from_upstream = Signal(providing_args=['user', ]) + # This signal fires whenever new user data has been received. Note that this # happens *after* first_name, last_name and email has been updated on the user # record, so those are not included in the userdata struct. @@ -104,10 +109,15 @@ def auth_receive(request): return HttpResponse("Missing data in url!", status=400) # Set up an AES object and decrypt the data we received - decryptor = AES.new(base64.b64decode(settings.PGAUTH_KEY), - AES.MODE_CBC, - base64.b64decode(str(request.GET['i']), "-_")) - s = decryptor.decrypt(base64.b64decode(str(request.GET['d']), "-_")).rstrip(b' ').decode('utf8') + try: + decryptor = AES.new(base64.b64decode(settings.PGAUTH_KEY), + AES.MODE_CBC, + base64.b64decode(str(request.GET['i']), "-_")) + s = decryptor.decrypt(base64.b64decode(str(request.GET['d']), "-_")).rstrip(b' ').decode('utf8') + except UnicodeDecodeError: + return HttpResponse("Badly encoded data found", 400) + except Exception: + return HttpResponse("Could not decrypt data", status=400) # Now un-urlencode it try: @@ -174,9 +184,7 @@ We apologize for the inconvenience. ) user.save() - # Subscribe to changes right away, so we get sent things like the - # ssh key which is not available in the inline data. - subscribe_to_user_changes(user.username) + auth_user_created_from_upstream.send(user) # Ok, we have a proper user record. Now tell django that # we're authenticated so it persists it in the session. Before @@ -221,13 +229,16 @@ def auth_api(request): except Exception: return HttpResponse("Invalid signature header!", status=400) - h = hmac.digest( - base64.b64decode(settings.PGAUTH_KEY), - msg=request.body, - digest='sha512', - ) - if not hmac.compare_digest(h, sig): - return HttpResponse("Invalid signature!", status=401) + try: + h = hmac.digest( + base64.b64decode(settings.PGAUTH_KEY), + msg=request.body, + digest='sha512', + ) + if not hmac.compare_digest(h, sig): + return HttpResponse("Invalid signature!", status=401) + except Exception: + return HttpResponse("Unable to compute hmac", status=400) try: pushstruct = json.loads(request.body) @@ -282,7 +293,7 @@ def auth_api(request): # Unlike the authentication, searching does not involve the browser - we just make # a direct http call. def user_search(searchterm=None, userid=None): - # If upsteam isn't responding quickly, it's not going to respond at all, and + # If upstream isn't responding quickly, it's not going to respond at all, and # 10 seconds is already quite long. socket.setdefaulttimeout(10) if userid: @@ -351,19 +362,15 @@ def user_import(uid): if User.objects.filter(username=u['u']).exists(): raise Exception("User already exists") - u = User(username=u['u'], - first_name=u['f'], - last_name=u['l'], - email=u['e'], - password='setbypluginnotsha1', + u = User( + username=u['u'], + first_name=u['f'], + last_name=u['l'], + email=u['e'], + password='setbypluginnotsha1', ) u.save() - # Trigger a subscription on the main website so we get updates for this user - try: - subscribe_to_user_changes(uid) - except Exception as e: - # We ignore the actual error, but let's log it. - print("Exception subscribing new user: %s", e) + auth_user_created_from_upstream.send(user) return u -- 2.39.5