Coverage for paperless/signals.py: 21%
49 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 09:07 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 09:07 +0000
1import logging
3from django.conf import settings
4from python_ipware import IpWare
6logger = logging.getLogger("paperless.auth")
9# https://docs.djangoproject.com/en/4.1/ref/contrib/auth/#django.contrib.auth.signals.user_login_failed
10def handle_failed_login(sender, credentials, request, **kwargs):
11 ipware = IpWare(proxy_list=settings.TRUSTED_PROXIES)
12 client_ip, _ = ipware.get_client_ip(
13 meta=request.META,
14 )
15 username = credentials.get("username")
16 log_output = (
17 "No authentication provided"
18 if username is None
19 else f"Login failed for user `{username}`"
20 )
22 if client_ip is None: 22 ↛ 23line 22 didn't jump to line 23 because the condition on line 22 was never true
23 log_output += ". Unable to determine IP address."
24 else:
25 if client_ip.is_global: 25 ↛ 27line 25 didn't jump to line 27 because the condition on line 25 was never true
26 # We got the client's IP address
27 log_output += f" from IP `{client_ip}`."
28 else:
29 # The client's IP address is private
30 log_output += f" from private IP `{client_ip}`."
32 logger.info(log_output)
35def handle_social_account_updated(sender, request, sociallogin, **kwargs):
36 """
37 Handle the social account update signal.
38 """
39 from django.contrib.auth.models import Group
41 if not sociallogin.user.is_active:
42 # allauth looks up and updates the social account, firing this
43 # signal, before checking if the user is allowed to actually log
44 # in. Syncing groups/roles here would arm a deactivated account
45 # with permissions it never exercised, which would silently take
46 # effect if the account is later reactivated for an unrelated
47 # reason.
48 logger.debug(
49 f"Skipping social account sync for inactive user `{sociallogin.user}`",
50 )
51 return
53 extra_data = sociallogin.account.extra_data or {}
54 social_account_groups = extra_data.get(
55 settings.SOCIAL_ACCOUNT_SYNC_GROUPS_CLAIM,
56 [],
57 ) # pre-allauth 65.11.0 structure
59 if not social_account_groups:
60 # allauth 65.11.0+ nests claims under `userinfo`/`id_token`
61 social_account_groups = (
62 extra_data.get("userinfo", {}).get(
63 settings.SOCIAL_ACCOUNT_SYNC_GROUPS_CLAIM,
64 )
65 or extra_data.get("id_token", {}).get(
66 settings.SOCIAL_ACCOUNT_SYNC_GROUPS_CLAIM,
67 )
68 or []
69 )
71 if isinstance(social_account_groups, str):
72 social_account_groups = [social_account_groups]
74 if settings.SOCIAL_ACCOUNT_SYNC_GROUPS and social_account_groups is not None:
75 groups = Group.objects.filter(name__in=social_account_groups)
76 logger.debug(
77 f"Syncing groups for user `{sociallogin.user}`: {social_account_groups}",
78 )
79 sociallogin.user.groups.set(groups, clear=True)
81 modified_fields = []
82 if settings.SOCIAL_ACCOUNT_SYNC_SUPERUSER_GROUP:
83 is_superuser = (
84 settings.SOCIAL_ACCOUNT_SYNC_SUPERUSER_GROUP in social_account_groups
85 )
86 if sociallogin.user.is_superuser != is_superuser:
87 sociallogin.user.is_superuser = is_superuser
88 modified_fields.append("is_superuser")
90 if settings.SOCIAL_ACCOUNT_SYNC_STAFF_GROUP:
91 is_staff = (
92 settings.SOCIAL_ACCOUNT_SYNC_STAFF_GROUP in social_account_groups
93 ) or sociallogin.user.is_superuser
94 if sociallogin.user.is_staff != is_staff:
95 sociallogin.user.is_staff = is_staff
96 modified_fields.append("is_staff")
97 elif settings.SOCIAL_ACCOUNT_SYNC_SUPERUSER_GROUP:
98 is_staff = sociallogin.user.is_superuser or sociallogin.user.is_staff
99 if sociallogin.user.is_staff != is_staff:
100 sociallogin.user.is_staff = is_staff
101 modified_fields.append("is_staff")
103 if modified_fields:
104 logger.debug(
105 f"Syncing roles for user `{sociallogin.user}`: superuser={sociallogin.user.is_superuser}, staff={sociallogin.user.is_staff}",
106 )
107 sociallogin.user.save(update_fields=modified_fields)