mirror of
https://github.com/eitchtee/WYGIWYH.git
synced 2026-02-23 16:04:56 +01:00
76 lines
2.8 KiB
Python
76 lines
2.8 KiB
Python
import logging
|
|
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
|
|
from django.contrib.auth import get_user_model
|
|
|
|
User = get_user_model()
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class AutoConnectSocialAccountAdapter(DefaultSocialAccountAdapter):
|
|
"""
|
|
Custom adapter to automatically connect social accounts to existing users
|
|
with the same email address.
|
|
|
|
SECURITY WARNING:
|
|
This adapter automatically connects OIDC accounts to existing local accounts
|
|
based on email matching.
|
|
|
|
If your OIDC provider allows unverified emails, this could lead to
|
|
ACCOUNT TAKEOVER attacks where an attacker creates an OIDC account
|
|
with someone else's email and gains access to their account.
|
|
"""
|
|
|
|
def pre_social_login(self, request, sociallogin):
|
|
"""
|
|
Invoked just after a user successfully authenticates via a
|
|
social provider, but before the login is actually processed.
|
|
|
|
If a user with the same email already exists, connect the social
|
|
account to that existing user instead of creating a new account.
|
|
"""
|
|
# If the social account is already connected to a user, do nothing
|
|
if sociallogin.is_existing:
|
|
return
|
|
|
|
# Check if we have an email from the social provider
|
|
if not sociallogin.email_addresses:
|
|
logger.warning(
|
|
"OIDC login attempted without email address. "
|
|
f"Provider: {sociallogin.account.provider}"
|
|
)
|
|
return
|
|
|
|
# Get the email from the social login
|
|
email = sociallogin.email_addresses[0].email.lower()
|
|
|
|
# Try to find an existing user with this email
|
|
try:
|
|
user = User.objects.get(email__iexact=email)
|
|
|
|
# Log this connection for security audit trail
|
|
logger.info(
|
|
f"Auto-connecting OIDC account to existing user. "
|
|
f"Email: {email}, Provider: {sociallogin.account.provider}, "
|
|
f"User ID: {user.id}"
|
|
)
|
|
|
|
# Connect the social account to the existing user
|
|
sociallogin.connect(request, user)
|
|
|
|
except User.DoesNotExist:
|
|
# No user with this email exists, proceed with normal signup flow
|
|
logger.debug(
|
|
f"No existing user found for email {email}. "
|
|
"Proceeding with new account creation."
|
|
)
|
|
pass
|
|
except User.MultipleObjectsReturned:
|
|
# Multiple users with the same email (shouldn't happen with unique constraint)
|
|
logger.error(
|
|
f"Multiple users found with email {email}. "
|
|
"This should not happen with unique constraint. "
|
|
"Blocking auto-connect."
|
|
)
|
|
# Let the default behavior handle this
|
|
pass
|