mirror of https://github.com/zulip/zulip.git
registration: Populate LDAP users using invitation information.
Fixes: #11212.
This commit is contained in:
parent
3e3d8527b0
commit
fcf2ffe8db
|
@ -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()
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue