emails: Cover all LDAP cases when emailing login details.

This provides a nice user experience for folks where we do know what
their LDAP credentials are.

Though we need to fix #10917 before the content in the email with be
correct.
This commit is contained in:
Vishnu Ks 2018-11-29 21:02:17 +05:30 committed by Tim Abbott
parent 7a2d93ed6e
commit f3033207b9
4 changed files with 96 additions and 15 deletions

View File

@ -22,10 +22,14 @@
<p> <p>
{{ _('Your account details:') }} {{ _('Your account details:') }}
<li>{{ _('Organization URL:') }} {{ realm_uri }}<br/></li> <li>{{ _('Organization URL:') }} {{ realm_uri }}<br/></li>
{% if ldap_username %} {% if ldap %}
<li>{{ _('Use your LDAP account to login') }}<br/></li> {% if ldap_username %}
<li>{{ _('Username:') }} {{ ldap_username }}<br/></li>
{% else %}
<li>{{ _('Use your LDAP account to login') }}<br/></li>
{% endif %}
{% else %} {% else %}
<li>{{ _('Email:') }} {{ email }}<br/></li> <li>{{ _('Email:') }} {{ email }}<br/></li>
{% endif %} {% endif %}
{% trans %} {% trans %}
(you'll need these to sign in to the <a href="https://zulipchat.com/apps">mobile and desktop</a> apps) (you'll need these to sign in to the <a href="https://zulipchat.com/apps">mobile and desktop</a> apps)

View File

@ -12,8 +12,12 @@ You've joined the Zulip organization {{ realm_name }}.
{{ _('Your account details:') }} {{ _('Your account details:') }}
* {{ _('Organization URL:') }} {{ realm_uri }} * {{ _('Organization URL:') }} {{ realm_uri }}
{% if ldap %}
{% if ldap_username %} {% if ldap_username %}
* {{ _('LDAP username:') }} {{ ldap_username }} * {{ _('Username:') }} {{ ldap_username }}
{% else %}
* {{ _('Use your LDAP account to login') }}
{% endif %}
{% else %} {% else %}
* {{ _('Email:') }} {{ email }} * {{ _('Email:') }} {{ email }}
{% endif %} {% endif %}

View File

@ -523,8 +523,15 @@ def enqueue_welcome_emails(user: UserProfile, realm_creation: bool=False) -> Non
context['getting_started_link'] = "https://zulipchat.com" context['getting_started_link'] = "https://zulipchat.com"
from zproject.backends import email_belongs_to_ldap, require_email_format_usernames from zproject.backends import email_belongs_to_ldap, require_email_format_usernames
if email_belongs_to_ldap(user.realm, user.email) and not require_email_format_usernames(user.realm):
context["ldap_username"] = True if email_belongs_to_ldap(user.realm, user.email):
context["ldap"] = True
if settings.LDAP_APPEND_DOMAIN:
for backend in get_backends():
if isinstance(backend, LDAPBackend):
context["ldap_username"] = backend.django_to_ldap_username(user.email)
elif not settings.LDAP_EMAIL_ATTR:
context["ldap_username"] = user.email
send_future_email( send_future_email(
"zerver/emails/followup_day1", user.realm, to_user_id=user.id, from_name=from_name, "zerver/emails/followup_day1", user.realm, to_user_id=user.id, from_name=from_name,

View File

@ -3,11 +3,13 @@ import os
import random import random
import re import re
import ujson import ujson
import ldap
from django.conf import settings from django.conf import settings
from django.core import mail from django.core import mail
from django.http import HttpResponse from django.http import HttpResponse
from django.test import override_settings from django.test import override_settings
from django_auth_ldap.config import LDAPSearch
from email.utils import formataddr from email.utils import formataddr
from mock import patch, MagicMock from mock import patch, MagicMock
from typing import Any, Dict, List, Optional from typing import Any, Dict, List, Optional
@ -52,12 +54,43 @@ class TestFollowupEmails(ZulipTestCase):
"http://zulip.testserver/help/getting-your-organization-started-with-zulip") "http://zulip.testserver/help/getting-your-organization-started-with-zulip")
self.assertNotIn("ldap_username", email_data["context"]) self.assertNotIn("ldap_username", email_data["context"])
# See https://zulip.readthedocs.io/en/latest/production/authentication-methods.html#ldap-including-active-directory
# for case details.
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend', @override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',
'zproject.backends.ZulipDummyBackend')) 'zproject.backends.ZulipDummyBackend'))
def test_day1_email_ldap_login_credentials(self) -> None: def test_day1_email_ldap_case_a_login_credentials(self) -> None:
password = "testing" ldap_user_attr_map = {'full_name': 'fn', 'short_name': 'sn'}
email = "newuser@zulip.com"
ldap_patcher = patch('django_auth_ldap.config.ldap.initialize')
mock_initialize = ldap_patcher.start()
mock_ldap = MockLDAP()
mock_initialize.return_value = mock_ldap
mock_ldap.directory = {
"uid=newuser@zulip.com,ou=users,dc=zulip,dc=com": {
'userPassword': 'testing',
'fn': ['full_name'],
'sn': ['shortname'],
}
}
ldap_search = LDAPSearch("ou=users,dc=zulip,dc=com", ldap.SCOPE_SUBTREE, "(email=%(user)s)")
with self.settings(
AUTH_LDAP_USER_ATTR_MAP=ldap_user_attr_map,
AUTH_LDAP_USER_DN_TEMPLATE='uid=%(user)s,ou=users,dc=zulip,dc=com',
AUTH_LDAP_USER_SEARCH=ldap_search):
self.login_with_return("newuser@zulip.com", "testing")
user = UserProfile.objects.get(email="newuser@zulip.com")
scheduled_emails = ScheduledEmail.objects.filter(user=user)
self.assertEqual(len(scheduled_emails), 2)
email_data = ujson.loads(scheduled_emails[0].data)
self.assertEqual(email_data["context"]["ldap"], True)
self.assertEqual(email_data["context"]["ldap_username"], "newuser@zulip.com")
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',
'zproject.backends.ZulipDummyBackend'))
def test_day1_email_ldap_case_b_login_credentials(self) -> None:
ldap_user_attr_map = {'full_name': 'fn', 'short_name': 'sn'} ldap_user_attr_map = {'full_name': 'fn', 'short_name': 'sn'}
ldap_patcher = patch('django_auth_ldap.config.ldap.initialize') ldap_patcher = patch('django_auth_ldap.config.ldap.initialize')
@ -65,11 +98,10 @@ class TestFollowupEmails(ZulipTestCase):
mock_ldap = MockLDAP() mock_ldap = MockLDAP()
mock_initialize.return_value = mock_ldap mock_initialize.return_value = mock_ldap
full_name = 'New LDAP fullname'
mock_ldap.directory = { mock_ldap.directory = {
'uid=newuser,ou=users,dc=zulip,dc=com': { 'uid=newuser,ou=users,dc=zulip,dc=com': {
'userPassword': 'testing', 'userPassword': 'testing',
'fn': [full_name], 'fn': ['full_name'],
'sn': ['shortname'], 'sn': ['shortname'],
} }
} }
@ -78,14 +110,48 @@ class TestFollowupEmails(ZulipTestCase):
LDAP_APPEND_DOMAIN='zulip.com', LDAP_APPEND_DOMAIN='zulip.com',
AUTH_LDAP_USER_ATTR_MAP=ldap_user_attr_map, AUTH_LDAP_USER_ATTR_MAP=ldap_user_attr_map,
AUTH_LDAP_USER_DN_TEMPLATE='uid=%(user)s,ou=users,dc=zulip,dc=com'): AUTH_LDAP_USER_DN_TEMPLATE='uid=%(user)s,ou=users,dc=zulip,dc=com'):
self.login_with_return(email, password)
user = UserProfile.objects.get(email=email) self.login_with_return("newuser@zulip.com", "testing")
user = UserProfile.objects.get(email="newuser@zulip.com")
scheduled_emails = ScheduledEmail.objects.filter(user=user) scheduled_emails = ScheduledEmail.objects.filter(user=user)
self.assertEqual(len(scheduled_emails), 2) self.assertEqual(len(scheduled_emails), 2)
email_data = ujson.loads(scheduled_emails[0].data) email_data = ujson.loads(scheduled_emails[0].data)
self.assertEqual(email_data["context"]["ldap_username"], True) self.assertEqual(email_data["context"]["ldap"], True)
self.assertEqual(email_data["context"]["ldap_username"], "newuser")
@override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend',
'zproject.backends.ZulipDummyBackend'))
def test_day1_email_ldap_case_c_login_credentials(self) -> None:
ldap_user_attr_map = {'full_name': 'fn', 'short_name': 'sn'}
ldap_patcher = patch('django_auth_ldap.config.ldap.initialize')
mock_initialize = ldap_patcher.start()
mock_ldap = MockLDAP()
mock_initialize.return_value = mock_ldap
mock_ldap.directory = {
'uid=newuser,ou=users,dc=zulip,dc=com': {
'userPassword': 'testing',
'fn': ['full_name'],
'sn': ['shortname'],
'email': ['newuser_email@zulip.com'],
}
}
with self.settings(
LDAP_EMAIL_ATTR='email',
AUTH_LDAP_USER_ATTR_MAP=ldap_user_attr_map,
AUTH_LDAP_USER_DN_TEMPLATE='uid=%(user)s,ou=users,dc=zulip,dc=com'):
self.login_with_return("newuser", "testing")
user = UserProfile.objects.get(email="newuser_email@zulip.com")
scheduled_emails = ScheduledEmail.objects.filter(user=user)
self.assertEqual(len(scheduled_emails), 2)
email_data = ujson.loads(scheduled_emails[0].data)
self.assertEqual(email_data["context"]["ldap"], True)
self.assertNotIn("ldap_username", email_data["context"])
def test_followup_emails_count(self) -> None: def test_followup_emails_count(self) -> None:
hamlet = self.example_user("hamlet") hamlet = self.example_user("hamlet")