import logging from django.conf import settings from python_ipware import IpWare logger = logging.getLogger("paperless.auth") # https://docs.djangoproject.com/en/4.1/ref/contrib/auth/#django.contrib.auth.signals.user_login_failed def handle_failed_login(sender, credentials, request, **kwargs): ipware = IpWare(proxy_list=settings.TRUSTED_PROXIES) client_ip, _ = ipware.get_client_ip( meta=request.META, ) username = credentials.get("username") log_output = ( "No authentication provided" if username is None else f"Login failed for user `{username}`" ) if client_ip is None: log_output += ". Unable to determine IP address." else: if client_ip.is_global: # We got the client's IP address log_output += f" from IP `{client_ip}`." else: # The client's IP address is private log_output += f" from private IP `{client_ip}`." logger.info(log_output) def handle_social_account_updated(sender, request, sociallogin, **kwargs): """ Handle the social account update signal. """ from django.contrib.auth.models import Group if not sociallogin.user.is_active: # allauth looks up and updates the social account, firing this # signal, before checking if the user is allowed to actually log # in. Syncing groups/roles here would arm a deactivated account # with permissions it never exercised, which would silently take # effect if the account is later reactivated for an unrelated # reason. logger.debug( f"Skipping social account sync for inactive user `{sociallogin.user}`", ) return extra_data = sociallogin.account.extra_data or {} social_account_groups = extra_data.get( settings.SOCIAL_ACCOUNT_SYNC_GROUPS_CLAIM, [], ) # pre-allauth 65.11.0 structure if not social_account_groups: # allauth 65.11.0+ nests claims under `userinfo`/`id_token` social_account_groups = ( extra_data.get("userinfo", {}).get( settings.SOCIAL_ACCOUNT_SYNC_GROUPS_CLAIM, ) or extra_data.get("id_token", {}).get( settings.SOCIAL_ACCOUNT_SYNC_GROUPS_CLAIM, ) or [] ) if isinstance(social_account_groups, str): social_account_groups = [social_account_groups] if settings.SOCIAL_ACCOUNT_SYNC_GROUPS and social_account_groups is not None: groups = Group.objects.filter(name__in=social_account_groups) logger.debug( f"Syncing groups for user `{sociallogin.user}`: {social_account_groups}", ) sociallogin.user.groups.set(groups, clear=True) modified_fields = [] if settings.SOCIAL_ACCOUNT_SYNC_SUPERUSER_GROUP: is_superuser = ( settings.SOCIAL_ACCOUNT_SYNC_SUPERUSER_GROUP in social_account_groups ) if sociallogin.user.is_superuser != is_superuser: sociallogin.user.is_superuser = is_superuser modified_fields.append("is_superuser") if settings.SOCIAL_ACCOUNT_SYNC_STAFF_GROUP: is_staff = ( settings.SOCIAL_ACCOUNT_SYNC_STAFF_GROUP in social_account_groups ) or sociallogin.user.is_superuser if sociallogin.user.is_staff != is_staff: sociallogin.user.is_staff = is_staff modified_fields.append("is_staff") elif settings.SOCIAL_ACCOUNT_SYNC_SUPERUSER_GROUP: is_staff = sociallogin.user.is_superuser or sociallogin.user.is_staff if sociallogin.user.is_staff != is_staff: sociallogin.user.is_staff = is_staff modified_fields.append("is_staff") if modified_fields: logger.debug( f"Syncing roles for user `{sociallogin.user}`: superuser={sociallogin.user.is_superuser}, staff={sociallogin.user.is_staff}", ) sociallogin.user.save(update_fields=modified_fields)