registration: Populate LDAP users using invitation information.

Fixes: #11212.
This commit is contained in:
Harshit Bansal 2019-01-16 08:59:01 +00:00 committed by Tim Abbott
parent 3e3d8527b0
commit fcf2ffe8db
4 changed files with 98 additions and 7 deletions

View File

@ -2125,10 +2125,11 @@ class ZulipLDAPTestCase(ZulipTestCase):
self.mock_ldap = MockLDAP() self.mock_ldap = MockLDAP()
self.mock_initialize.return_value = self.mock_ldap self.mock_initialize.return_value = self.mock_ldap
self.backend = ZulipLDAPAuthBackend() self.backend = ZulipLDAPAuthBackend()
# Internally `_realm` attribute is automatically set by the # Internally `_realm` and `_prereg_user` attributes are automatically set
# `authenticate()` method. But for testing the `get_or_build_user()` # by the `authenticate()` method. But for testing the `get_or_build_user()`
# method separately, we need to set it manually. # method separately, we need to set them manually.
self.backend._realm = get_realm('zulip') self.backend._realm = get_realm('zulip')
self.backend._prereg_user = None
def tearDown(self) -> None: def tearDown(self) -> None:
self.mock_ldap.reset() self.mock_ldap.reset()

View File

@ -21,7 +21,7 @@ from confirmation.models import Confirmation, create_confirmation_link, Multiuse
from confirmation import settings as confirmation_settings from confirmation import settings as confirmation_settings
from zerver.forms import HomepageForm, WRONG_SUBDOMAIN_ERROR, check_subdomain_available from zerver.forms import HomepageForm, WRONG_SUBDOMAIN_ERROR, check_subdomain_available
from zerver.lib.actions import do_change_password from zerver.lib.actions import do_change_password, get_default_streams_for_realm
from zerver.lib.exceptions import CannotDeactivateLastUserError from zerver.lib.exceptions import CannotDeactivateLastUserError
from zerver.lib.dev_ldap_directory import init_fakeldap from zerver.lib.dev_ldap_directory import init_fakeldap
from zerver.decorator import do_two_factor_login from zerver.decorator import do_two_factor_login
@ -59,6 +59,7 @@ from zerver.lib.mobile_auth_otp import xor_hex_strings, ascii_to_hex, \
from zerver.lib.notifications import enqueue_welcome_emails, \ from zerver.lib.notifications import enqueue_welcome_emails, \
followup_day2_email_delay followup_day2_email_delay
from zerver.lib.subdomains import is_root_domain_available from zerver.lib.subdomains import is_root_domain_available
from zerver.lib.stream_subscription import get_stream_subscriptions_for_user
from zerver.lib.test_helpers import find_key_by_email, queries_captured, \ from zerver.lib.test_helpers import find_key_by_email, queries_captured, \
HostRequestMock, load_subdomain_token HostRequestMock, load_subdomain_token
from zerver.lib.test_classes import ( from zerver.lib.test_classes import (
@ -2778,6 +2779,83 @@ class UserSignUpTest(ZulipTestCase):
# Name comes from the POST request, not LDAP # Name comes from the POST request, not LDAP
self.assertEqual(user_profile.full_name, 'Non-LDAP Full Name') self.assertEqual(user_profile.full_name, 'Non-LDAP Full Name')
def ldap_invite_and_signup_as(self, invite_as: int, streams: List[str]=['Denmark']) -> None:
ldap_user_attr_map = {'full_name': 'fn'}
mock_directory = {
'uid=newuser,ou=users,dc=zulip,dc=com': {
'userPassword': ['testing'],
'fn': ['LDAP Name'],
}
}
init_fakeldap(mock_directory)
subdomain = 'zulip'
email = self.nonreg_email('newuser')
password = 'testing'
# Invite user.
self.login(self.example_email('iago'))
response = self.client_post("/json/invites",
{"invitee_emails": [self.nonreg_email('newuser')],
"stream": streams,
"invite_as": invite_as})
self.assert_json_success(response)
self.logout()
with self.settings(
POPULATE_PROFILE_VIA_LDAP=True,
LDAP_APPEND_DOMAIN='zulip.com',
AUTH_LDAP_BIND_PASSWORD='',
AUTH_LDAP_USER_ATTR_MAP=ldap_user_attr_map,
AUTH_LDAP_USER_DN_TEMPLATE='uid=%(user)s,ou=users,dc=zulip,dc=com'):
result = self.submit_reg_form_for_user(email,
password,
full_name="Ignore",
from_confirmation="1",
# Pass HTTP_HOST for the target subdomain
HTTP_HOST=subdomain + ".testserver")
self.assertEqual(result.status_code, 200)
result = self.submit_reg_form_for_user(email,
password,
full_name="Ignore",
# Pass HTTP_HOST for the target subdomain
HTTP_HOST=subdomain + ".testserver")
self.assertEqual(result.status_code, 302)
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',
'zproject.backends.EmailAuthBackend'))
def test_ldap_invite_user_as_admin(self) -> None:
self.ldap_invite_and_signup_as(PreregistrationUser.INVITE_AS['REALM_ADMIN'])
user_profile = UserProfile.objects.get(email=self.nonreg_email('newuser'))
self.assertTrue(user_profile.is_realm_admin)
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',
'zproject.backends.EmailAuthBackend'))
def test_ldap_invite_user_as_guest(self) -> None:
self.ldap_invite_and_signup_as(PreregistrationUser.INVITE_AS['GUEST_USER'])
user_profile = UserProfile.objects.get(email=self.nonreg_email('newuser'))
self.assertTrue(user_profile.is_guest)
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',
'zproject.backends.EmailAuthBackend'))
def test_ldap_invite_streams(self) -> None:
stream_name = 'Rome'
realm = get_realm('zulip')
stream = get_stream(stream_name, realm)
default_streams = get_default_streams_for_realm(realm)
default_streams_name = [stream.name for stream in default_streams]
self.assertNotIn(stream_name, default_streams_name)
# Invite user.
self.ldap_invite_and_signup_as(PreregistrationUser.INVITE_AS['REALM_ADMIN'], streams=[stream_name])
user_profile = UserProfile.objects.get(email=self.nonreg_email('newuser'))
self.assertTrue(user_profile.is_realm_admin)
sub = get_stream_subscriptions_for_user(user_profile).filter(recipient__type_id=stream.id)
self.assertEqual(len(sub), 1)
def test_registration_when_name_changes_are_disabled(self) -> None: def test_registration_when_name_changes_are_disabled(self) -> None:
""" """
Test `name_changes_disabled` when we are not running under LDAP. Test `name_changes_disabled` when we are not running under LDAP.

View File

@ -244,6 +244,7 @@ def accounts_register(request: HttpRequest) -> HttpResponse:
username=email, username=email,
password=password, password=password,
realm=realm, realm=realm,
prereg_user=prereg_user,
return_data=return_data) return_data=return_data)
if auth_result is not None: if auth_result is not None:
# Since we'll have created a user, we now just log them in. # Since we'll have created a user, we now just log them in.

View File

@ -24,8 +24,9 @@ from zerver.lib.dev_ldap_directory import init_fakeldap
from zerver.lib.request import JsonableError from zerver.lib.request import JsonableError
from zerver.lib.subdomains import user_matches_subdomain, get_subdomain from zerver.lib.subdomains import user_matches_subdomain, get_subdomain
from zerver.lib.users import check_full_name from zerver.lib.users import check_full_name
from zerver.models import UserProfile, Realm, get_user_profile_by_id, \ from zerver.models import PreregistrationUser, UserProfile, Realm, get_default_stream_groups, \
remote_user_to_email, email_to_username, get_realm, get_user_by_delivery_email get_user_profile_by_id, remote_user_to_email, email_to_username, get_realm, \
get_user_by_delivery_email
def pad_method_dict(method_dict: Dict[str, bool]) -> Dict[str, bool]: def pad_method_dict(method_dict: Dict[str, bool]) -> Dict[str, bool]:
"""Pads an authentication methods dict to contain all auth backends """Pads an authentication methods dict to contain all auth backends
@ -364,10 +365,12 @@ class ZulipLDAPAuthBackend(ZulipLDAPAuthBackendBase):
REALM_IS_NONE_ERROR = 1 REALM_IS_NONE_ERROR = 1
def authenticate(self, username: str, password: str, realm: Optional[Realm]=None, def authenticate(self, username: str, password: str, realm: Optional[Realm]=None,
prereg_user: Optional[PreregistrationUser]=None,
return_data: Optional[Dict[str, Any]]=None) -> Optional[UserProfile]: return_data: Optional[Dict[str, Any]]=None) -> Optional[UserProfile]:
if realm is None: if realm is None:
return None return None
self._realm = realm self._realm = realm
self._prereg_user = prereg_user
if not ldap_auth_enabled(realm): if not ldap_auth_enabled(realm):
return None return None
@ -430,7 +433,15 @@ class ZulipLDAPAuthBackend(ZulipLDAPAuthBackendBase):
except JsonableError as e: except JsonableError as e:
raise ZulipLDAPException(e.msg) raise ZulipLDAPException(e.msg)
user_profile = do_create_user(username, None, self._realm, full_name, short_name) opts = {} # type: Dict[str, Any]
if self._prereg_user:
invited_as = self._prereg_user.invited_as
opts['prereg_user'] = self._prereg_user
opts['is_realm_admin'] = invited_as == PreregistrationUser.INVITE_AS['REALM_ADMIN']
opts['is_guest'] = invited_as == PreregistrationUser.INVITE_AS['GUEST_USER']
opts['default_stream_groups'] = get_default_stream_groups(self._realm)
user_profile = do_create_user(username, None, self._realm, full_name, short_name, **opts)
self.sync_avatar_from_ldap(user_profile, ldap_user) self.sync_avatar_from_ldap(user_profile, ldap_user)
return user_profile, True return user_profile, True