mirror of https://github.com/zulip/zulip.git
[manual] Support authentication and profile prefilling via LDAP
The latter doesn't depend on the former; we can still fill in your full name even if you didn't authenticate via LDAP. This commit requires django_auth_ldap to be installed. On Debian systems, you can do so via APT: sudo apt-get install python-django-auth-ldap On OS X, use your favourite package manager. For pip, I believe this will work: pip install django_auth_ldap django_auth_ldap depends on the "ldap" Python package, which should be installed automatically on your system. (imported from commit 43967754285990b06b5a920abe95b8bce44e2053)
This commit is contained in:
parent
e711b8160a
commit
af02e45a17
|
@ -57,6 +57,8 @@ class zulip::app_frontend {
|
|||
"python-apns-client",
|
||||
# Needed for avatar image resizing
|
||||
"python-imaging",
|
||||
# Needed for LDAP support
|
||||
"python-django-auth-ldap",
|
||||
]
|
||||
define safepackage ( $ensure = present ) {
|
||||
if !defined(Package[$title]) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import authenticate, login
|
||||
from django.contrib.auth import authenticate, login, get_backends
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponseRedirect, HttpResponseForbidden, HttpResponse
|
||||
|
@ -46,6 +46,7 @@ from zerver.forms import RegistrationForm, HomepageForm, ToSForm, \
|
|||
CreateBotForm, is_inactive
|
||||
from django.views.decorators.csrf import csrf_exempt, csrf_protect
|
||||
from django_openid_auth.views import default_render_failure, login_complete
|
||||
from django_auth_ldap.backend import LDAPBackend, _LDAPUser
|
||||
from openid.consumer.consumer import SUCCESS as openid_SUCCESS
|
||||
from openid.extensions import ax
|
||||
from zerver.lib import bugdown
|
||||
|
@ -251,8 +252,19 @@ def accounts_register(request):
|
|||
hesiod_name = compute_mit_user_fullname(email)
|
||||
form = RegistrationForm(
|
||||
initial={'full_name': hesiod_name if "@" not in hesiod_name else ""})
|
||||
elif settings.POPULATE_PROFILE_VIA_LDAP:
|
||||
for backend in get_backends():
|
||||
if isinstance(backend, LDAPBackend):
|
||||
ldap_attrs = _LDAPUser(backend, backend.django_to_ldap_username(email)).attrs
|
||||
# TODO: check if ldap_attributes are none
|
||||
form = RegistrationForm(
|
||||
initial={'full_name': ldap_attrs[
|
||||
settings.AUTH_LDAP_USER_ATTR_MAP['full_name']
|
||||
][0]})
|
||||
break
|
||||
else:
|
||||
form = RegistrationForm()
|
||||
|
||||
else:
|
||||
form = RegistrationForm(request.POST)
|
||||
if form.is_valid():
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from django.contrib.auth.backends import RemoteUserBackend
|
||||
from django.conf import settings
|
||||
import django.contrib.auth
|
||||
|
||||
from django_auth_ldap.backend import LDAPBackend
|
||||
|
||||
from zerver.models import UserProfile, get_user_profile_by_id, \
|
||||
get_user_profile_by_email, remote_user_to_email
|
||||
get_user_profile_by_email, remote_user_to_email, email_to_username
|
||||
|
||||
from openid.consumer.consumer import SUCCESS
|
||||
|
||||
|
@ -77,3 +80,26 @@ class ZulipRemoteUserBackend(RemoteUserBackend):
|
|||
return get_user_profile_by_email(email)
|
||||
except UserProfile.DoesNotExist:
|
||||
return None
|
||||
|
||||
class ZulipLDAPAuthBackend(ZulipAuthMixin, LDAPBackend):
|
||||
def django_to_ldap_username(self, username):
|
||||
if settings.LDAP_APPEND_DOMAIN is not None:
|
||||
return email_to_username(username)
|
||||
return username
|
||||
|
||||
def ldap_to_django_username(self, username):
|
||||
if settings.LDAP_APPEND_DOMAIN is not None:
|
||||
return username + settings.LDAP_APPEND_DOMAIN
|
||||
return username
|
||||
|
||||
def get_or_create_user(self, username, ldap_user):
|
||||
try:
|
||||
return get_user_profile_by_email(username), False
|
||||
except UserProfile.DoesNotExist:
|
||||
return UserProfile(), False
|
||||
|
||||
class ZulipLDAPUserPopulator(ZulipLDAPAuthBackend):
|
||||
# Just like ZulipLDAPAuthBackend, but doesn't let you log in.
|
||||
|
||||
def authenticate(self, username, password):
|
||||
return None
|
||||
|
|
|
@ -22,6 +22,7 @@ DEPLOYMENT_ROLE_KEY = ''
|
|||
AUTHENTICATION_BACKENDS = (
|
||||
# 'zproject.backends.EmailAuthBackend', # Email and password
|
||||
# 'zproject.backends.ZulipRemoteUserBackend', # Local SSO
|
||||
# 'zproject.backends.ZulipLDAPAuthBackend', # LDAP authentication
|
||||
# 'zproject.backends.GoogleBackend', # Google Apps
|
||||
)
|
||||
|
||||
|
@ -136,6 +137,36 @@ EMAIL_GATEWAY_IMAP_PORT = 993
|
|||
# must be delivered to this folder
|
||||
EMAIL_GATEWAY_IMAP_FOLDER = "INBOX"
|
||||
|
||||
### LDAP integration configuration
|
||||
# Zulip supports retrieving information about users via LDAP, and optionally
|
||||
# using LDAP as an authentication mechanism.
|
||||
|
||||
import ldap
|
||||
from django_auth_ldap.config import LDAPSearch, GroupOfNamesType
|
||||
|
||||
# URI of your LDAP server. If set, LDAP is used to prepopulate a user's name in
|
||||
# Zulip. Example: "ldaps://ldap.example.com"
|
||||
AUTH_LDAP_SERVER_URI = ""
|
||||
|
||||
# This DN and password will be used to bind to your server. If unset, anonymous
|
||||
# binds are performed.
|
||||
AUTH_LDAP_BIND_DN = ""
|
||||
AUTH_LDAP_BIND_PASSWORD = ""
|
||||
|
||||
# Specify the search base and the property to filter on that corrisponds to the
|
||||
# username.
|
||||
AUTH_LDAP_USER_SEARCH = LDAPSearch("ou=users,dc=example,dc=com",
|
||||
ldap.SCOPE_SUBTREE, "(uid=%(user)s)")
|
||||
|
||||
# If the value of a user's "uid" (or similar) property is not their email
|
||||
# address, specify the domain to append here.
|
||||
LDAP_APPEND_DOMAIN = SSO_APPEND_DOMAIN
|
||||
|
||||
AUTH_LDAP_USER_ATTR_MAP = {
|
||||
# Populate the Django user's name from the LDAP directory.
|
||||
"full_name": "cn",
|
||||
}
|
||||
|
||||
# The following secrets are randomly generated during the install
|
||||
# process, are used for security purposes, and should not be shared
|
||||
# with anyone.
|
||||
|
|
|
@ -267,6 +267,7 @@ DEFAULT_SETTINGS = {'TWITTER_CONSUMER_KEY': '',
|
|||
'ENABLE_FEEDBACK': True,
|
||||
'ENABLE_GRAVATAR': True,
|
||||
'DEFAULT_AVATAR_URI': '/static/images/default-avatar.png',
|
||||
'AUTH_LDAP_BIND_DN': "",
|
||||
}
|
||||
|
||||
for setting_name, setting_val in DEFAULT_SETTINGS.iteritems():
|
||||
|
@ -733,6 +734,14 @@ else:
|
|||
ONLY_SSO = False
|
||||
AUTHENTICATION_BACKENDS += ('guardian.backends.ObjectPermissionBackend',)
|
||||
|
||||
POPULATE_PROFILE_VIA_LDAP = bool(AUTH_LDAP_BIND_DN)
|
||||
|
||||
if POPULATE_PROFILE_VIA_LDAP and \
|
||||
not 'zproject.backends.ZulipLDAPAuthBackend' in AUTHENTICATION_BACKENDS:
|
||||
AUTHENTICATION_BACKENDS += ('zproject.backends.ZulipLDAPUserPopulator',)
|
||||
else:
|
||||
POPULATE_PROFILE_VIA_LDAP = 'zproject.backends.ZulipLDAPAuthBackend' in AUTHENTICATION_BACKENDS or POPULATE_PROFILE_VIA_LDAP
|
||||
|
||||
if DEPLOYED:
|
||||
FULL_NAVBAR = False
|
||||
else:
|
||||
|
|
Loading…
Reference in New Issue