mirror of
https://github.com/zulip/zulip.git
synced 2025-11-06 23:13:25 +00:00
auth: Make multiuse invite link work with oAuth2.
This works by attaching to the user's session the multi-use invitation key, allowing that to be used in the Google/GitHub auth flows.
This commit is contained in:
@@ -23,6 +23,7 @@ from zerver.lib.actions import (
|
|||||||
do_reactivate_realm,
|
do_reactivate_realm,
|
||||||
do_reactivate_user,
|
do_reactivate_user,
|
||||||
do_set_realm_authentication_methods,
|
do_set_realm_authentication_methods,
|
||||||
|
create_stream_if_needed,
|
||||||
)
|
)
|
||||||
from zerver.lib.mobile_auth_otp import otp_decrypt_api_key
|
from zerver.lib.mobile_auth_otp import otp_decrypt_api_key
|
||||||
from zerver.lib.validator import validate_login_email, \
|
from zerver.lib.validator import validate_login_email, \
|
||||||
@@ -36,9 +37,9 @@ from zerver.lib.test_classes import (
|
|||||||
from zerver.lib.test_helpers import POSTRequestMock
|
from zerver.lib.test_helpers import POSTRequestMock
|
||||||
from zerver.models import \
|
from zerver.models import \
|
||||||
get_realm, email_to_username, UserProfile, \
|
get_realm, email_to_username, UserProfile, \
|
||||||
PreregistrationUser, Realm, get_user
|
PreregistrationUser, Realm, get_user, MultiuseInvite
|
||||||
|
|
||||||
from confirmation.models import Confirmation, confirmation_url
|
from confirmation.models import Confirmation, confirmation_url, create_confirmation_link
|
||||||
|
|
||||||
from zproject.backends import ZulipDummyBackend, EmailAuthBackend, \
|
from zproject.backends import ZulipDummyBackend, EmailAuthBackend, \
|
||||||
GoogleMobileOauth2Backend, ZulipRemoteUserBackend, ZulipLDAPAuthBackend, \
|
GoogleMobileOauth2Backend, ZulipRemoteUserBackend, ZulipLDAPAuthBackend, \
|
||||||
@@ -994,6 +995,69 @@ class GoogleSubdomainLoginTest(GoogleOAuthTest):
|
|||||||
self.assert_not_in_success_response(['id_password'], result)
|
self.assert_not_in_success_response(['id_password'], result)
|
||||||
self.assert_in_success_response(['id_full_name'], result)
|
self.assert_in_success_response(['id_full_name'], result)
|
||||||
|
|
||||||
|
@override_settings(REALMS_HAVE_SUBDOMAINS=True)
|
||||||
|
def test_log_into_subdomain_when_using_invite_link(self):
|
||||||
|
# type: () -> None
|
||||||
|
data = {'name': 'New User Name',
|
||||||
|
'email': 'new@zulip.com',
|
||||||
|
'subdomain': 'zulip',
|
||||||
|
'is_signup': True}
|
||||||
|
|
||||||
|
realm = get_realm("zulip")
|
||||||
|
realm.invite_required = True
|
||||||
|
realm.save()
|
||||||
|
|
||||||
|
stream_names = ["new_stream_1", "new_stream_2"]
|
||||||
|
streams = []
|
||||||
|
for stream_name in set(stream_names):
|
||||||
|
stream, _ = create_stream_if_needed(realm, stream_name)
|
||||||
|
streams.append(stream)
|
||||||
|
|
||||||
|
self.client.cookies = SimpleCookie(self.get_signed_subdomain_cookie(data))
|
||||||
|
|
||||||
|
# Without the invite link, we can't create an account due to invite_required
|
||||||
|
result = self.client_get('/accounts/login/subdomain/', subdomain="zulip")
|
||||||
|
self.assertEqual(result.status_code, 200)
|
||||||
|
self.assert_in_success_response(['Sign up for Zulip'], result)
|
||||||
|
|
||||||
|
# Now confirm an invitation link works
|
||||||
|
referrer = self.example_user("hamlet")
|
||||||
|
multiuse_obj = MultiuseInvite.objects.create(realm=realm, referred_by=referrer)
|
||||||
|
multiuse_obj.streams = streams
|
||||||
|
multiuse_obj.save()
|
||||||
|
invite_link = create_confirmation_link(multiuse_obj, realm.host,
|
||||||
|
Confirmation.MULTIUSE_INVITE)
|
||||||
|
|
||||||
|
result = self.client_get(invite_link, subdomain="zulip")
|
||||||
|
self.assert_in_success_response(['Sign up for Zulip'], result)
|
||||||
|
|
||||||
|
result = self.client_get('/accounts/login/subdomain/', subdomain="zulip")
|
||||||
|
self.assertEqual(result.status_code, 302)
|
||||||
|
|
||||||
|
confirmation = Confirmation.objects.all().last()
|
||||||
|
confirmation_key = confirmation.confirmation_key
|
||||||
|
self.assertIn('do_confirm/' + confirmation_key, result.url)
|
||||||
|
result = self.client_get(result.url)
|
||||||
|
self.assert_in_response('action="/accounts/register/"', result)
|
||||||
|
data2 = {"from_confirmation": "1",
|
||||||
|
"full_name": data['name'],
|
||||||
|
"key": confirmation_key}
|
||||||
|
result = self.client_post('/accounts/register/', data2, subdomain="zulip")
|
||||||
|
self.assert_in_response("You're almost there", result)
|
||||||
|
|
||||||
|
# Verify that the user is asked for name but not password
|
||||||
|
self.assert_not_in_success_response(['id_password'], result)
|
||||||
|
self.assert_in_success_response(['id_full_name'], result)
|
||||||
|
|
||||||
|
# Click confirm registration button.
|
||||||
|
result = self.client_post(
|
||||||
|
'/accounts/register/',
|
||||||
|
{'full_name': 'New User Name',
|
||||||
|
'key': confirmation_key,
|
||||||
|
'terms': True})
|
||||||
|
self.assertEqual(result.status_code, 302)
|
||||||
|
self.assertEqual(sorted(self.get_streams('new@zulip.com', realm)), stream_names)
|
||||||
|
|
||||||
@override_settings(REALMS_HAVE_SUBDOMAINS=True)
|
@override_settings(REALMS_HAVE_SUBDOMAINS=True)
|
||||||
def test_log_into_subdomain_when_email_is_none(self):
|
def test_log_into_subdomain_when_email_is_none(self):
|
||||||
# type: () -> None
|
# type: () -> None
|
||||||
|
|||||||
@@ -47,7 +47,19 @@ import ujson
|
|||||||
|
|
||||||
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
|
||||||
form = HomepageForm({'email': email}, realm=get_realm_from_request(request))
|
|
||||||
|
realm = get_realm_from_request(request)
|
||||||
|
from_multiuse_invite = False
|
||||||
|
multiuse_obj = None
|
||||||
|
streams_to_subscribe = None
|
||||||
|
multiuse_object_key = request.session.get("multiuse_object_key", None)
|
||||||
|
if multiuse_object_key is not None:
|
||||||
|
from_multiuse_invite = True
|
||||||
|
multiuse_obj = Confirmation.objects.get(confirmation_key=multiuse_object_key).content_object
|
||||||
|
realm = multiuse_obj.realm
|
||||||
|
streams_to_subscribe = multiuse_obj.streams.all()
|
||||||
|
|
||||||
|
form = HomepageForm({'email': email}, realm=realm, from_multiuse_invite=from_multiuse_invite)
|
||||||
request.verified_email = None
|
request.verified_email = None
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
# Construct a PreregistrationUser object and send the user over to
|
# Construct a PreregistrationUser object and send the user over to
|
||||||
@@ -63,6 +75,13 @@ def maybe_send_to_registration(request, email, full_name='', password_required=T
|
|||||||
prereg_user = create_preregistration_user(email, request,
|
prereg_user = create_preregistration_user(email, request,
|
||||||
password_required=password_required)
|
password_required=password_required)
|
||||||
|
|
||||||
|
if multiuse_object_key is not None:
|
||||||
|
del request.session["multiuse_object_key"]
|
||||||
|
request.session.modified = True
|
||||||
|
if streams_to_subscribe is not None:
|
||||||
|
prereg_user.streams = streams_to_subscribe
|
||||||
|
prereg_user.save()
|
||||||
|
|
||||||
return redirect("".join((
|
return redirect("".join((
|
||||||
create_confirmation_link(prereg_user, request.get_host(), Confirmation.USER_REGISTRATION),
|
create_confirmation_link(prereg_user, request.get_host(), Confirmation.USER_REGISTRATION),
|
||||||
'?full_name=',
|
'?full_name=',
|
||||||
@@ -73,7 +92,8 @@ def maybe_send_to_registration(request, email, full_name='', password_required=T
|
|||||||
url = reverse('register')
|
url = reverse('register')
|
||||||
return render(request,
|
return render(request,
|
||||||
'zerver/accounts_home.html',
|
'zerver/accounts_home.html',
|
||||||
context={'form': form, 'current_url': lambda: url},
|
context={'form': form, 'current_url': lambda: url,
|
||||||
|
'from_multiuse_invite': from_multiuse_invite},
|
||||||
)
|
)
|
||||||
|
|
||||||
def redirect_to_subdomain_login_url():
|
def redirect_to_subdomain_login_url():
|
||||||
|
|||||||
@@ -402,6 +402,8 @@ def accounts_home_from_multiuse_invite(request, confirmation_key):
|
|||||||
multiuse_object = None
|
multiuse_object = None
|
||||||
try:
|
try:
|
||||||
multiuse_object = get_object_from_key(confirmation_key)
|
multiuse_object = get_object_from_key(confirmation_key)
|
||||||
|
# Required for oAuth2
|
||||||
|
request.session["multiuse_object_key"] = confirmation_key
|
||||||
except ConfirmationKeyException as exception:
|
except ConfirmationKeyException as exception:
|
||||||
realm = get_realm_from_request(request)
|
realm = get_realm_from_request(request)
|
||||||
if realm is None or realm.invite_required:
|
if realm is None or realm.invite_required:
|
||||||
|
|||||||
Reference in New Issue
Block a user