mirror of
https://github.com/zulip/zulip.git
synced 2025-11-17 20:41:46 +00:00
registration: Check realm against PreregistrationUser realm.
We would allow a user with a valid invitation for one realm to use it on a different realm instead. On a server with multiple realms, an authorized user of one realm could use this (by sending invites to other email addresses they control) to create accounts on other realms. (CVE-2017-0910) With this commit, when sending an invitation, we record the inviting user's realm on the PreregistrationUser row; and when registering a user, we check that the PregistrationUser realm matches the realm the user is trying to register on. This resolves CVE-2017-0910 for newly-sent invitations; the next commit completes the fix. [greg: rewrote commit message]
This commit is contained in:
@@ -4000,7 +4000,8 @@ def do_invite_users(user_profile, invitee_emails, streams, invite_as_admin=False
|
|||||||
for email in validated_emails:
|
for email in validated_emails:
|
||||||
# The logged in user is the referrer.
|
# The logged in user is the referrer.
|
||||||
prereg_user = PreregistrationUser(email=email, referred_by=user_profile,
|
prereg_user = PreregistrationUser(email=email, referred_by=user_profile,
|
||||||
invited_as_admin=invite_as_admin)
|
invited_as_admin=invite_as_admin,
|
||||||
|
realm=user_profile.realm)
|
||||||
|
|
||||||
prereg_user.save()
|
prereg_user.save()
|
||||||
stream_ids = [stream.id for stream in streams]
|
stream_ids = [stream.id for stream in streams]
|
||||||
|
|||||||
@@ -353,7 +353,7 @@ class LoginTest(ZulipTestCase):
|
|||||||
with queries_captured() as queries:
|
with queries_captured() as queries:
|
||||||
self.register(self.nonreg_email('test'), "test")
|
self.register(self.nonreg_email('test'), "test")
|
||||||
# Ensure the number of queries we make is not O(streams)
|
# Ensure the number of queries we make is not O(streams)
|
||||||
self.assert_length(queries, 65)
|
self.assert_length(queries, 67)
|
||||||
user_profile = self.nonreg_user('test')
|
user_profile = self.nonreg_user('test')
|
||||||
self.assertEqual(get_session_dict_user(self.client.session), user_profile.id)
|
self.assertEqual(get_session_dict_user(self.client.session), user_profile.id)
|
||||||
self.assertFalse(user_profile.enable_stream_desktop_notifications)
|
self.assertFalse(user_profile.enable_stream_desktop_notifications)
|
||||||
@@ -1691,6 +1691,22 @@ class UserSignUpTest(ZulipTestCase):
|
|||||||
mock_error.assert_called_once()
|
mock_error.assert_called_once()
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
|
|
||||||
|
def test_replace_subdomain_in_confirmation_link(self) -> None:
|
||||||
|
"""
|
||||||
|
Check that manually changing the subdomain in a registration
|
||||||
|
confirmation link doesn't allow you to register to a different realm.
|
||||||
|
"""
|
||||||
|
email = "newuser@zulip.com"
|
||||||
|
self.client_post('/accounts/home/', {'email': email})
|
||||||
|
result = self.client_post(
|
||||||
|
'/accounts/register/',
|
||||||
|
{'password': "password",
|
||||||
|
'key': find_key_by_email(email),
|
||||||
|
'terms': True,
|
||||||
|
'full_name': "New User",
|
||||||
|
'from_confirmation': '1'}, subdomain="zephyr")
|
||||||
|
self.assert_in_success_response(["We couldn't find your confirmation link"], result)
|
||||||
|
|
||||||
def test_failed_signup_due_to_restricted_domain(self) -> None:
|
def test_failed_signup_due_to_restricted_domain(self) -> None:
|
||||||
realm = get_realm('zulip')
|
realm = get_realm('zulip')
|
||||||
realm.invite_required = False
|
realm.invite_required = False
|
||||||
|
|||||||
@@ -48,9 +48,13 @@ import ujson
|
|||||||
def create_preregistration_user(email, request, realm_creation=False,
|
def create_preregistration_user(email, request, realm_creation=False,
|
||||||
password_required=True):
|
password_required=True):
|
||||||
# type: (Text, HttpRequest, bool, bool) -> HttpResponse
|
# type: (Text, HttpRequest, bool, bool) -> HttpResponse
|
||||||
|
realm = None
|
||||||
|
if not realm_creation:
|
||||||
|
realm = get_realm(get_subdomain(request))
|
||||||
return PreregistrationUser.objects.create(email=email,
|
return PreregistrationUser.objects.create(email=email,
|
||||||
realm_creation=realm_creation,
|
realm_creation=realm_creation,
|
||||||
password_required=password_required)
|
password_required=password_required,
|
||||||
|
realm=realm)
|
||||||
|
|
||||||
def maybe_send_to_registration(request, email, full_name='', password_required=True):
|
def maybe_send_to_registration(request, email, full_name='', password_required=True):
|
||||||
# type: (HttpRequest, Text, Text, bool) -> HttpResponse
|
# type: (HttpRequest, Text, Text, bool) -> HttpResponse
|
||||||
@@ -74,7 +78,7 @@ def maybe_send_to_registration(request, email, full_name='', password_required=T
|
|||||||
prereg_user = None
|
prereg_user = None
|
||||||
if settings.ONLY_SSO:
|
if settings.ONLY_SSO:
|
||||||
try:
|
try:
|
||||||
prereg_user = PreregistrationUser.objects.filter(email__iexact=email).latest("invited_at")
|
prereg_user = PreregistrationUser.objects.filter(email__iexact=email, realm=realm).latest("invited_at")
|
||||||
except PreregistrationUser.DoesNotExist:
|
except PreregistrationUser.DoesNotExist:
|
||||||
prereg_user = create_preregistration_user(email, request,
|
prereg_user = create_preregistration_user(email, request,
|
||||||
password_required=password_required)
|
password_required=password_required)
|
||||||
|
|||||||
@@ -59,15 +59,13 @@ def accounts_register(request):
|
|||||||
is_realm_admin = prereg_user.invited_as_admin or realm_creation
|
is_realm_admin = prereg_user.invited_as_admin or realm_creation
|
||||||
|
|
||||||
validators.validate_email(email)
|
validators.validate_email(email)
|
||||||
if prereg_user.referred_by:
|
if realm_creation:
|
||||||
# If someone invited you, you are joining their realm regardless
|
|
||||||
# of your e-mail address.
|
|
||||||
realm = prereg_user.referred_by.realm
|
|
||||||
elif realm_creation:
|
|
||||||
# For creating a new realm, there is no existing realm or domain
|
# For creating a new realm, there is no existing realm or domain
|
||||||
realm = None
|
realm = None
|
||||||
else:
|
else:
|
||||||
realm = get_realm(get_subdomain(request))
|
realm = get_realm(get_subdomain(request))
|
||||||
|
if prereg_user.realm is not None and prereg_user.realm != realm:
|
||||||
|
return render(request, 'confirmation/link_does_not_exist.html')
|
||||||
|
|
||||||
if realm and not email_allowed_for_realm(email, realm):
|
if realm and not email_allowed_for_realm(email, realm):
|
||||||
return render(request, "zerver/closed_realm.html",
|
return render(request, "zerver/closed_realm.html",
|
||||||
|
|||||||
Reference in New Issue
Block a user