Skip to content
Snippets Groups Projects

Handle wrong person following invitation link

Merged Andreas Ellewsen requested to merge GREG-166-invitation-theft-prevention into master
All threads resolved!
Files
3
@@ -10,13 +10,13 @@ from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import BaseBackend, UserModel
from django.core.exceptions import SuspiciousOperation
from django.utils.timezone import make_aware
from django.utils import timezone
from mozilla_django_oidc.auth import OIDCAuthenticationBackend
from greg.models import Identity, Person, Sponsor, InvitationLink
from gregui.models import GregUserProfile
from gregui.utils import name_diff
from gregui.utils import name_diff_too_large
logger = structlog.getLogger(__name__)
@@ -339,7 +339,7 @@ class GregOIDCBackend(ValidatingOIDCBackend):
existing_nin.source = source
existing_nin.value = new_nin
existing_nin.verified = Identity.Verified.AUTOMATIC
existing_nin.verified_at = make_aware(datetime.datetime.now())
existing_nin.verified_at = timezone.make_aware(datetime.datetime.now())
existing_nin.save()
logger.info("identity_update", identity_id=existing_nin.id)
@@ -357,7 +357,7 @@ class GregOIDCBackend(ValidatingOIDCBackend):
type=Identity.IdentityType.NORWEGIAN_NATIONAL_ID_NUMBER,
value=new_nin,
verified=Identity.Verified.AUTOMATIC,
verified_at=make_aware(datetime.datetime.now()),
verified_at=timezone.make_aware(datetime.datetime.now()),
)
nin_id.save()
logger.info("identity_add", identity_id=nin_id.id)
@@ -399,7 +399,7 @@ class GregOIDCBackend(ValidatingOIDCBackend):
existing_feide_id.source = source
existing_feide_id.value = new_feide_id
existing_feide_id.verified = Identity.Verified.AUTOMATIC
existing_feide_id.verified_at = make_aware(datetime.datetime.now())
existing_feide_id.verified_at = timezone.make_aware(datetime.datetime.now())
existing_feide_id.save()
else:
@@ -421,7 +421,7 @@ class GregOIDCBackend(ValidatingOIDCBackend):
type=Identity.IdentityType.FEIDE_ID,
value=new_feide_id,
verified=Identity.Verified.AUTOMATIC,
verified_at=make_aware(datetime.datetime.now()),
verified_at=timezone.make_aware(datetime.datetime.now()),
)
feide_id.save()
logger.info("identity_add", identity_id=feide_id.id, feide_id=new_feide_id)
@@ -445,7 +445,7 @@ class GregOIDCBackend(ValidatingOIDCBackend):
old_email = existing_email.value
existing_email.value = new_email
existing_email.verified = Identity.Verified.AUTOMATIC
existing_email.verified_at = make_aware(datetime.datetime.now())
existing_email.verified_at = timezone.make_aware(datetime.datetime.now())
existing_email.save()
logger.info(
"identity_update",
@@ -472,19 +472,19 @@ class GregOIDCBackend(ValidatingOIDCBackend):
type=Identity.IdentityType.FEIDE_EMAIL,
value=new_email,
verified=Identity.Verified.AUTOMATIC,
verified_at=make_aware(datetime.datetime.now()),
verified_at=timezone.make_aware(datetime.datetime.now()),
)
email_id.save()
logger.info("identity_add", identity_id=email_id.id, value=new_email)
def _update_person_name(
self, person: Person, first_name: str, last_name: str, source: str
self, person: Person, first_name: str, last_name: str
) -> None:
new_combined_name = f"{first_name} {last_name}"
existing_combined_name = f"{person.first_name} {person.last_name}"
if name_diff(existing_combined_name, new_combined_name) > 4:
if name_diff_too_large(existing_combined_name, new_combined_name, 4):
logger.warning(
"name_diff_to_large",
existing_name=existing_combined_name,
@@ -518,9 +518,7 @@ class GregOIDCBackend(ValidatingOIDCBackend):
self._update_person_feide_id(person, userinfo["userid_feide"], "feide")
if "email" in userinfo:
self._update_person_email(person, userinfo["email"], "feide")
self._update_person_name(
person, userinfo["first_name"], userinfo["last_name"], "feide"
)
self._update_person_name(person, userinfo["first_name"], userinfo["last_name"])
def _update_sponsor_from_userinfo(self, userinfo: dict, sponsor: Sponsor) -> None:
"""Updates a sponsor object with data from OIDC."""
@@ -578,26 +576,19 @@ class GregOIDCBackend(ValidatingOIDCBackend):
def _get_or_create_greg_user_profile(self, userinfo: dict, user: UserModel):
"""Get or create a GregUserProfile."""
def _get_invite_person(
session, old_person: Optional[Person]
) -> Optional[Person]:
def _get_invitation_link(session) -> Optional[InvitationLink]:
try:
invitation_link = InvitationLink.objects.get(uuid=session["invite_id"])
return InvitationLink.objects.get(uuid=session["invite_id"])
except InvitationLink.DoesNotExist:
logger.error("invite_not_found", invite_id=session["invite_id"])
logger.bind(authenticating_invite=False)
return old_person
return None
def _get_invite_person(invitation_link) -> Person:
logger.bind(authenticating_invite=True)
role = invitation_link.invitation.role
invite_person = role.person
logger.info("invite_found", invite_person=invite_person.id)
if old_person and not old_person == invite_person:
role.person = old_person
role.save()
invite_person.delete()
return old_person
return invite_person
logger.bind(user=user)
@@ -618,7 +609,49 @@ class GregOIDCBackend(ValidatingOIDCBackend):
old_person = None
if user_profile and user_profile.person:
old_person = self._get_person_from_userinfo(userinfo)
person = _get_invite_person(session, old_person)
person = old_person
invitation_link = _get_invitation_link(session)
if invitation_link:
inv_person = _get_invite_person(invitation_link)
if old_person and old_person != inv_person:
# Logged in person has a person object in greg but has followed an
# invite.
inv_name = f"{inv_person.first_name} {inv_person.last_name}"
old_name = f"{old_person.first_name} {old_person.last_name}"
if (
not inv_person.registration_completed_date
and not name_diff_too_large(old_name, inv_name, 4)
):
logger.info(
"Invitation (%s) opened by existing person (%s)."
" Giving role to them and deleting invited person (%s)",
invitation_link.invitation.id,
old_person.id,
inv_person.id,
)
# The name is close and the invited person has not completed
# registration. Give the role to the existing person, and
# delete the invited one.
role = invitation_link.invitation.role
role.person = old_person
role.save()
inv_person.delete()
else:
# The logged in user has gotten someone else's invitation, and
# the invitation should be disabled.
logger.warning(
"Illegal person accessed invitation (%s). Invitation belongs to"
" person id %s, but was access by person id %s. Expiring"
" InvitationLink %s.",
invitation_link.invitation.id,
inv_person.id,
old_person.id,
invitation_link.id,
)
invitation_link.expire = timezone.now()
invitation_link.save()
else:
person = inv_person
else:
person = self._get_person_from_userinfo(userinfo)
logger.bind(authenticating_invite=False)
Loading