-
-
Notifications
You must be signed in to change notification settings - Fork 84
fix: allow social account linking only to useraccounts of type PERSON
#1484
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,18 +7,21 @@ | |
| from allauth.account import app_settings | ||
| from allauth.account.adapter import DefaultAccountAdapter | ||
| from allauth.account.models import EmailConfirmationHMAC | ||
| from allauth.core.exceptions import ImmediateHttpResponse | ||
| from allauth.socialaccount.adapter import DefaultSocialAccountAdapter | ||
| from allauth.socialaccount.models import SocialLogin | ||
| from allauth.socialaccount.providers.oauth2.provider import OAuth2Provider | ||
| from constance import config | ||
| from django.contrib import messages | ||
| from django.contrib.auth.models import AbstractUser | ||
| from django.core.exceptions import ValidationError | ||
| from django.http import HttpRequest | ||
| from django.shortcuts import redirect | ||
| from django.utils import timezone | ||
| from invitations.adapters import BaseInvitationsAdapter | ||
|
|
||
| from qfieldcloud.authentication.sso.provider_styles import SSOProviderStyles | ||
| from qfieldcloud.core.models import Person | ||
| from qfieldcloud.core.models import Person, User | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
@@ -194,6 +197,47 @@ class SocialAccountAdapter(DefaultSocialAccountAdapter): | |
| Logs stack trace and error details on 3rd party authentication errors. | ||
| """ | ||
|
|
||
| def pre_social_login(self, request: HttpRequest, sociallogin: SocialLogin) -> None: | ||
| """ | ||
| Invoked just after a user successfully authenticates via a | ||
| social provider, but before the login is actually processed | ||
| (and before the pre_social_login signal is emitted). | ||
|
|
||
| This is a good hook to check that the user is of type `PERSON`, | ||
| and not of type `ORGANIZATION` or `TEAM`, | ||
| as SSO login should only be allowed for user accounts. | ||
| """ | ||
|
|
||
| # check if allauth can find a useraccount with this email, | ||
| # meaning that the accounts would be linked and a social account created. | ||
| if sociallogin.is_existing: | ||
| # here we check that the user trying to login is of type `PERSON`. | ||
| user = sociallogin.user | ||
|
|
||
| if user.type != User.Type.PERSON: | ||
| # if the user is not of type `PERSON`, | ||
| # we try to find a user with the same email that is of type `PERSON`, | ||
| # and link the social account to that user instead. | ||
| # Otherwise we block the social account link to an Organization. | ||
|
|
||
| email = sociallogin.account.extra_data.get("email", "") | ||
|
|
||
| if not email: | ||
| messages.error( | ||
| request, "No email returned by the Identity Provider." | ||
| ) | ||
| raise ImmediateHttpResponse(redirect("account_login")) | ||
|
|
||
| try: | ||
| person_user = User.objects.get(email=email, type=User.Type.PERSON) | ||
| sociallogin.user = person_user | ||
| except User.DoesNotExist: | ||
| messages.error( | ||
| request, | ||
| "Can login via SSO only to user accounts, not organizations.", | ||
| ) | ||
| raise ImmediateHttpResponse(redirect("account_login")) | ||
|
||
|
|
||
| def on_authentication_error( | ||
| self, | ||
| request: HttpRequest, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would try to emulate allauth's
SocialLogin._lookup_by_emailas much as possible here. And just where it gets the results fromfilter_users_by_emailthen filter that list of users to only keep the ones that matchtype == User.Type.PERSON.Because with this implementation, we're missing several parts of the functionality that allauth does during that lookup:
sociallogin._did_authenticate_by_email = email