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:
Vishnu Ks
2017-09-27 07:04:58 +05:30
committed by Tim Abbott
parent 945e97ec35
commit 94e099eaab
3 changed files with 90 additions and 4 deletions

View File

@@ -23,6 +23,7 @@ from zerver.lib.actions import (
do_reactivate_realm,
do_reactivate_user,
do_set_realm_authentication_methods,
create_stream_if_needed,
)
from zerver.lib.mobile_auth_otp import otp_decrypt_api_key
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.models import \
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, \
GoogleMobileOauth2Backend, ZulipRemoteUserBackend, ZulipLDAPAuthBackend, \
@@ -994,6 +995,69 @@ class GoogleSubdomainLoginTest(GoogleOAuthTest):
self.assert_not_in_success_response(['id_password'], 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)
def test_log_into_subdomain_when_email_is_none(self):
# type: () -> None

View File

@@ -47,7 +47,19 @@ import ujson
def maybe_send_to_registration(request, email, full_name='', password_required=True):
# 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
if form.is_valid():
# 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,
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((
create_confirmation_link(prereg_user, request.get_host(), Confirmation.USER_REGISTRATION),
'?full_name=',
@@ -73,7 +92,8 @@ def maybe_send_to_registration(request, email, full_name='', password_required=T
url = reverse('register')
return render(request,
'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():

View File

@@ -402,6 +402,8 @@ def accounts_home_from_multiuse_invite(request, confirmation_key):
multiuse_object = None
try:
multiuse_object = get_object_from_key(confirmation_key)
# Required for oAuth2
request.session["multiuse_object_key"] = confirmation_key
except ConfirmationKeyException as exception:
realm = get_realm_from_request(request)
if realm is None or realm.invite_required: